Colorpeek,第二部分:构建你的第一个 Chrome 扩展

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 $200 免费信用额度!

以下是 Tyler Sticka 的客座文章。Tyler 创建了一个名为 Colorpeek 的工具。 昨天我们介绍了 什么是它以及为什么要使用它。今天,我们将了解他是如何构建 Chrome 扩展的,这将作为您开始构建自己的 Chrome 扩展的绝佳教程。

第一部分 中,我展示了 Colorpeek,一个我用来快速共享 CSS 颜色的 Web 应用程序,以及 它的 Chrome 扩展,它使接收颜色变得同样容易。那么,一个自称是设计师优先于开发者的家伙是如何独自构建一个花哨的扩展的呢?

(向宜家致歉。)

事实证明,非常容易。Chrome 扩展程序主要是 JavaScript,而且是相对简单的 JavaScript。一开始,浏览 所有这些文档 可能令人望而生畏,但一旦您掌握了基础知识,您就会发现 Chrome 开发只是Web 开发,只是有一些独特的变化。

在这篇文章中,我们将构建我们自己的 Colorpeek 扩展的简化版本:background-colorpeek,一个用于查找和预览网页使用的所有background-color值的工具。您会惊讶于它多么简单。

你需要什么

  • Google Chrome.
  • 你喜欢的文本编辑器。
  • 一个用于存放扩展文件的文件目录。
  • 一个用于浏览器操作的图标,这是 Chrome 对浏览器工具栏中的按钮的称呼。它应该是一个 19 像素正方形的 PNG 图像。如果您愿意,可以使用此图标:

您可以现在创建所有需要的文件,也可以在后面创建它们……这完全取决于您。在我们完成时,我们的目录将看起来像这样

  • event.js
  • icon19.png
  • inject.js
  • manifest.json

准备好了吗?让我们开始吧!

清单文件

在目录的根目录下创建一个新文件,并将其命名为manifest.json。清单是任何 Chrome 扩展的核心。它告诉 Chrome“我是谁,我需要什么才能工作。”

让我们使用 JSON 添加一些细节到该文件

{
  "manifest_version": 2,

  "name": "background-colorpeek",
  "version": "1.0",
  "description": "Get every background-color from the current tab.",

  "browser_action": {
    "default_icon": "icon19.png"
  },

  "background": {
    "scripts": ["event.js"],
    "persistent": false
  },
  
  "permissions": ["<all_urls>"]
}

大多数属性是不言自明的,除了以下几个例外

  • manifest_version:这使 Chrome 了解我们使用的是哪个版本的清单文件格式。版本 1 在 Chrome 18 中被弃用,因此您应该始终使用版本 2。
  • background:有关扩展程序需要哪些脚本才能响应事件的信息,例如单击浏览器操作。稍后将详细介绍。
  • permissions:因为我们希望扩展程序从任何 URL 抓取background-color值,所以我们需要权限来与&lt;all_urls&gt;进行交互。如果我们希望扩展程序仅在https://css-tricks.org.cn/上工作,我们可以指定它。

您可以使用清单文件做更多的事情,请参阅这里,但这对于我们的扩展程序来说已经足够了。

脚本开始生效

您会注意到我们的清单引用了一个我们尚未创建的 JavaScript 文件,event.js。现在创建它,并向其中添加一些代码

// This function will eventually contain some logic
// for receiving background-color values from the
// current tab.
function getBgColors (tab) {
  // But for now, let's just make sure what we have so
  // far is working as expected.
  alert('The browser action was clicked! Yay!');
}

// When the browser action is clicked, call the
// getBgColors function.
chrome.browserAction.onClicked.addListener(getBgColors);

此脚本是 Chrome 所知的(有点令人困惑)事件页面。这意味着它只会在扩展程序关心的事件发生时运行……在本例中,就是单击浏览器操作。

在继续之前,我们应该在 Chrome 中加载扩展程序

  1. 打开chrome://extensions/(或单击最右边的菜单按钮,然后单击“工具”,然后单击“扩展程序”。)
  2. 确保右上角的“开发者模式”框已选中。
  3. 单击“加载解压缩扩展程序……”,然后选择您之前创建的目录。

如果一切顺利,扩展程序应该像任何其他扩展程序一样安装。单击浏览器操作(我们的图标)以查看一个神奇的警报

Alert: The browser action was clicked! Yay!

很酷吧?

标签交流

现在我们的浏览器操作已准备好听从我们的指示,我们需要从当前标签中检索 CSS 信息。为此,我们需要了解 Chrome 扩展程序相对于标签中加载的网页是如何工作的,以及它们之间是如何进行通信的。

Chrome 是第一个普及我们在当今桌面浏览器中理所当然的工具的浏览器:多进程架构。在 Chrome 中,每个网页、附加组件和扩展程序都有自己的进程。这使得非常难以让单个网页或扩展程序崩溃您的整个浏览器。但这也会使我们的事件页面成为一个孤岛……当标签的进程与event.js完全分离时,我们如何对标签的内容进行操作呢?

坏消息:我们做不到。

好消息:我们不需要这样做,因为 Chrome 支持在脚本之间传递消息。我们已经有了事件页面,可以用来发送消息。我们现在只需要一个可以在当前标签中接收消息的脚本!

作者对sendMessage的演绎。

以下是我们的巧妙消息传递是如何工作的

  1. 当用户单击浏览器操作时,event.js注入一个新的脚本到当前标签中,其中包含有关下一步操作的说明。
  2. 注入的脚本将执行它需要执行的操作,并返回我们请求的数据。

这意味着我们的扩展程序需要再添加一个文件,inject.js

// This helps avoid conflicts in case we inject 
// this script on the same page multiple times
// without reloading.
var injected = injected || (function(){

  // An object that will contain the "methods"
  // we can use from our event script.
  var methods = {};

  // This method will eventually return
  // background colors from the current page.
  methods.getBgColors = function(){
    var nodes = document.querySelectorAll('*');
    return nodes.length;
  };

  // This tells the script to listen for
  // messages from our extension.
  chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    var data = {};
    // If the method the extension has requested
    // exists, call it and assign its response
    // to data.
    if (methods.hasOwnProperty(request.method))
      data = methods[request.method]();
    // Send the response back to our extension.
    sendResponse({ data: data });
    return true;
  });

  return true;
})();

现在我们有一个准备接收命令并返回数据的脚本。让我们更新event.js以利用它

// Execute the inject.js in a tab and call a method,
// passing the result to a callback function.
function injectedMethod (tab, method, callback) {
  chrome.tabs.executeScript(tab.id, { file: 'inject.js' }, function(){
    chrome.tabs.sendMessage(tab.id, { method: method }, callback);
  });
}

function getBgColors (tab) {
  // When we get a result back from the getBgColors
  // method, alert the data
  injectedMethod(tab, 'getBgColors', function (response) {
    alert('Elements in tab: ' + response.data);
    return true;
  });
}

// When the browser action is clicked, call the
// getBgColors function.
chrome.browserAction.onClicked.addListener(getBgColors);

chrome://extensions/重新加载扩展程序,并在任何网页上尝试使用浏览器操作。您应该会看到一条包含 HTML 节点数的消息,这意味着我们已成功与标签进行了交互!太棒了!

终于做了一些很酷的事情

所有部分都已就位。现在是时候真正我们想要做的事情了

  1. 当单击浏览器操作时,确定当前标签的所有background-color值。
  2. 基于这些值构建一个 Colorpeek URL。
  3. 在新标签页中打开该 URL。

从现在开始,几乎没有魔法……实际上只是 JavaScript(甚至不是花哨的 jQuery)。让我们开始吧……

再次打开inject.js并更新getBgColors方法

// Return all of the background-color values
methods.getBgColors = function(){
  // Stores the colors and the number of occurrences
  var colors = {};
  // Get all the nodes on a page
  var nodes = document.querySelectorAll('*');
  // Instantiate variables we'll use later
  var node, nodeArea, bgColor, i;

  // Loop through all the nodes
  for (i = 0; i < nodes.length; i++) {
    // The current node
    node = nodes[i];
    // The area in pixels occupied by the element
    nodeArea = node.clientWidth * node.clientHeight;
    // The computed background-color value
    bgColor = window.getComputedStyle(node)['background-color'];
    // Strip spaces from the color for succinctness
    bgColor = bgColor.replace(/ /g, '');
    // If the color is not white or fully transparent...
    if (
      bgColor != 'rgb(255,255,255)' &&
      !(bgColor.indexOf('rgba') === 0 && bgColor.substr(-3) === ',0)')
    ) {
      // ...set or override it in the colors object,
      // adding the current element area to the
      // existing value.
      colors[bgColor] = (colors[bgColor] >> 0) + nodeArea;
    }
  }

  // Sort and return the colors by
  // total area descending
  return Object.getOwnPropertyNames(colors).sort(function (a, b) {
    return colors[b] - colors[a];
  });
}

我们快完成了!现在更新event.js中的getBgColors函数

// Get background-color values from the current tab
// and open them in Colorpeek.
function getBgColors (tab) {
  injectedMethod(tab, 'getBgColors', function (response) {
    var colors = response.data;
    if (colors && colors.length) {
      var url = 'http://colorpeek.com/#' + colors.join(',');
      chrome.tabs.create({ url: url });
    } else {
      alert('No background colors were found! :(');
    }
    return true;
  })
}

重新加载扩展程序并试一试。如果成功,就给自己泡杯饮料庆祝一下您新获得的制作 Chrome 扩展程序的能力吧!

CSS-Tricks 中使用的一些背景颜色值。

额外练习

这个扩展程序只是冰山一角。您可以使用 Chrome 的 平台 API 做很多事情。如果您的大脑仍然渴望知识,可以尝试以下一些事情

我希望这能帮助你解开 Chrome 扩展开发中的一些谜团。如果你喜欢我们一起构建的东西,请尝试一下 Chrome 版 Colorpeek… 我想你会喜欢的。祝你玩得愉快!