Please note, this is a STATIC archive of website developer.mozilla.org from November 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

演练

在本文中,我们将演练如何从头开始建立一个适用于 Firefox 的 WebExtension 扩展。

这个扩展会添加一个新按钮到 Firefox 的工具栏。在用户点击该按钮时,我们会显示一个弹出窗来让他们选择一种动物。在他们选择之后,我们会将当前网页的每个图片替换为他所选择的动物。

要实现这点,我们将:

  • 定义一个浏览器动作,这用来附加一个按钮到 Firefox 的工具栏。
    对于该按钮,我们将提供:
    • 一个图标,称它为 "beasts.png"
    • 按钮被按下时要打开的弹出窗。该弹出窗将包含 HTML、CSS 和 JavaScript。
  • 写一个内容脚本,即 "beastify.js" 将被注入到网页中。
    这是用来实际修改页面的代码。
  • 打包一些动物的图像,用以替换网页中的图像。
    我们将图像打包为“”Web 可访问资源“,以便页面可以引用它们。

你可以想象这样的扩展的整体结构:

这是一个非常简单的扩展,但也展示了 WebExtensions API 的许多基本概念:

  • 添加一个按钮到工具栏
  • 定义一个将使用 HTML、CSS 和 JavaScript 的弹出面板
  • 注入内容脚本到网页
  • 内容脚本与扩展的其他部分之间的通信
  • 打包你的扩展的资源,使其可被网页所用

你可以在 GitHub 找到该扩展的完整的源代码

前提条件

All you need is Firefox 45 or higher. See Your first WebExtension to get started.

编写 WebExtension

创建一个新目录,并切换到该目录:

mkdir beastify
cd beastify

manifest.json

现在创建一个名为 "manifest.json" 的文件,并给添加下列内容:

{

  "manifest_version": 2,
  "name": "Beastify",
  "version": "1.0",

  "applications": {
    "gecko": {
      "id": "[email protected]"
    }
  },

  "permissions": [
    "https://*/*",
    "https://*/*"
  ],  

  "browser_action": {
    "default_icon": "button/beasts.png",
    "default_title": "Beastify",
    "default_popup": "popup/choose_beast.html"
  },
  
  "web_accessible_resources": [
    "beasts/frog.jpg",
    "beasts/turtle.jpg",
    "beasts/snake.jpg"
  ]

}
  • 最开始的三个属性: manifest_version, name, version, 是必须的并且包含了插件最基本的信息。
  • description homepage_url 是可选的,但是推荐填写,因为它们提供有用的信息。
  • icons 也是可选但推荐的,它决定了插件在附加组件中的图标。
  • permissions 列出了插件所需要的权限。在这里我们需要的是 activeTab permission
  • browser_action 确定了工具栏按钮的响应。我们支持下面三种信息:
    • default_icon 是必须的,指定了按钮的图标。
    • default_title 是可选的,用于按钮的提示。
    • default_popup  是可选的,用于指定用户按下按钮后的弹出框,因此需要指定html文件。
  • web_accessible_resources 列出了页面可访问的资源。例如由于当前插件使用动物图像替换了页面原有的图像,当前的动物图像要可以被页面获得。

需要注意,所有路径是相对于 manifest.json 。

图标

插件应该有一个图标。这个图标被用于显示在附加组件管理器中(可以通过"about:addons"来访问)。当前插件中manifest.json指定了我们插件的图标位于"icons/beasts-48.png"。

创建“icons”文件夹,并将图标命名为“beasts-48.png”。你可以使用我们例子中的图标,它是从 Aha-Soft’s Free Retina iconset 截取的,使用需要遵循该网站的许可证

如果你使用自己的图标,它的尺寸应该是48×\times48像素的。同时,对于高分辨率的设备,可以提供96×\times96像素的图片。此时,manifest.json应当这样配置

"icons": {
  "48": "icons/beasts-48.png",
  "96": "icons/beasts-96.png"
}

 

工具栏按钮

工具栏按钮需要一个图标,并且我们的 manifest.json 承诺我们会为该工具栏在 "button/beasts.png" 提供一个图标。

创建这个 "button" 目录,将一个图标复制并更名为 "beasts.png"。你可以使用例子中的图片,它是取自 IconBeast Lite 图标集并按其许可协议授权使用。

  • 如果你没有弹出窗,用户点击的事件会直接分派到你的插件中
  • 如果你制作了弹出窗,用户点击会直接打开这个弹出窗,而不会被分派给插件

本例中我们需要弹出窗,因此我们现在开始写它。

弹出窗

该弹出窗的函数是让用户选择三种动物的其中一种。

在根目录下创建“popup”文件夹,用于存放弹出窗的代码。弹出窗由以下文件组成:

  • choose_beast.html 定义了界面的主面板
  • choose_beast.css 美化内容
  • choose_beast.js 通过内容脚本处理用户事件

choose_beast.html

HTML 文件可以这样:

<!DOCTYPE html>

<html>
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="choose_beast.css"/>
  </head>

  <body>
    <div class="beast">Frog</div>
    <div class="beast">Turtle</div>
    <div class="beast">Snake</div>

    <script src="choose_beast.js"></script>
  </body>

</html>

本例中我们对每种动物提供选择。可见看到,我们在其中加入了css和js文件,就像一个正常的网页

choose_beast.css

CSS 定义了弹出窗的大小,并且给三种选择安排了位置:

html, body {
  height: 100px;
  width: 100px;
  margin: 0;
}

.beast {
  height: 30%;
  width: 90%;
  margin: 3% auto;
  padding-top: 6%;
  text-align: center;
  font-size: 1.5em;
  background-color: #E5F2F2;
  cursor: pointer;
}

.beast:hover {
  background-color: #CFF2F2;
}

choose_beast.js

我们在弹出窗的脚本中监听点击事件。 如果用户选择其中一个动物,我们在当前标签页中插入一段内容脚本。一旦内容脚本加载,我们发送一条有关动物选择的信息:

/*
Given the name of a beast, get the URL to the corresponding image.
*/
function beastNameToURL(beastName) {
  switch (beastName) {
    case "Frog":
      return chrome.extension.getURL("beasts/frog.jpg");
    case "Snake":
      return chrome.extension.getURL("beasts/snake.jpg");
    case "Turtle":
      return chrome.extension.getURL("beasts/turtle.jpg");
  }
}

/*
Listen for clicks in the popup.

If the click is not on one of the beasts, return early.

Otherwise, the text content of the node is the name of the beast we want.

Inject the "beastify.js" content script in the active tab.

Then get the active tab and send "beastify.js" a message
containing the URL to the chosen beast's image.
*/
document.addEventListener("click", function(e) {
  if (!e.target.classList.contains("beast")) {
    return;
  }

  var chosenBeast = e.target.textContent;
  var chosenBeastURL = beastNameToURL(chosenBeast);

  chrome.tabs.executeScript(null, {
    file: "/content_scripts/beastify.js"
  });

  chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    chrome.tabs.sendMessage(tabs[0].id, {beastURL: chosenBeastURL});
  });

});

它使用这些 WebExtension API 函数:

  • chrome.tabs.executeScript 向当前标签页中插入指定位置的脚本,本例中为"/content_scripts/beastify.js"
  • chrome.tabs.query 根据条件查找标签页
  • chrome.tabs.sendMessage 向内容脚本发送信息。这里的信息包含了所选择图片的URL

内容脚本

在相应目录下创建名为"content_scripts"的文件夹,然后创建名为"beastify.js"的脚本,内容如下:

/*
beastify():
* removes every node in the document.body,
* then inserts the chosen beast
* then removes itself as a listener 
*/
function beastify(request, sender, sendResponse) {
  removeEverything();
  insertBeast(request.beastURL);
  chrome.runtime.onMessage.removeListener(beastify);
}

/*
Remove every node under document.body
*/
function removeEverything() {
  while (document.body.firstChild) {
    document.body.firstChild.remove();
  }
}

/*
Given a URL to a beast image, create and style an IMG node pointing to
that image, then insert the node into the document.
*/
function insertBeast(beastURL) {
  var beastImage = document.createElement("img");
  beastImage.setAttribute("src", beastURL);
  beastImage.setAttribute("style", "width: 100vw");
  beastImage.setAttribute("style", "height: 100vh");
  document.body.appendChild(beastImage);
}

/*
Assign beastify() as a listener for messages from the extension.
*/
chrome.runtime.onMessage.addListener(beastify);

内容脚本添加了监听信息的监听器。监听器做了以下工作:

  • 将 document.body 中的所有元素移除
  • 在 DOM 中创建指向图片URL的<img>标签
  • 移除它自己

动物们

最后,我们要加入包含动物们的图像。

创建"beasts"文件夹,之后将图片放入并命名。你可以从 the GitHub repository,或这里下载图片:

测试

请确认项目目录如下所示:

beastify/

    beasts/
        frog.jpg
        snake.jpg
        turtle.jpg

    content_scripts/
        beastify.js

    icons/
        beasts-32.png
        beasts-48.png

    popup/
        choose_beast.css
        choose_beast.html
        choose_beast.js

    manifest.json

打开 FireFox for developers,确保可以添加未知来源插件

在地址栏输入"about:debugging",之后点击"Load Temporary Add-on",之后选中 manifest.json 文件,你会在工具栏中看到插件被加载

随便打开一个页面,点击图标,选择喜爱的动物

打包和安装

再次确认目录正确并且已经测试:

beastify/

    beasts/
        frog.jpg
        snake.jpg
        turtle.jpg

    button/
        beasts.png

    content_scripts/
        beastify.js

    popup/
        choose_beast.css
        choose_beast.html
        choose_beast.js

    manifest.json

Firefox 插件以 ZIP 文件打包,之后需要将扩展名改为".xpi"。

需要注意的是需要在 beastify/ 文件夹内部打包,而不应该在文件夹外面(确保 manifest.json 在根目录):

   # in beastify/
   zip -r ../beastify.xpi *

你可以这样将XPI插件安装到Firefox,打开FireFox:

  • 从文件菜单选择 open 或 按下 Ctrl/Cmd+O
  • 在窗口中选择"beastify.xpi"

应该会收到安装未知来源插件的警告,接受它。

你现在应该看到图标已出现在 Firefox 的工具栏。打开一个网页,然后点击该图标,选择一种动物,然后看看网页中的所有图像。

 

 

 

文档标签和贡献者

 此页面的贡献者: CXWorks, GrayLight, yfdyh000
 最后编辑者: CXWorks,