起步

2014年2月28日星期五发布,2021年7月22日星期四更新

扩展程序是由各种不同但相互协作的组件构成的。这些组件包括 backgroud scripts,content script,一个 options page,UI元素和各种逻辑文件。扩展程序组件通过web开发技术所创建:HTML,CSS 和 JavaScript。扩展程序的组件存在与否根据程序的功能需求而定,并不要求扩展程序包含所有的组件。

本教程将构建一个扩展程序,允许用户改变当前聚焦页面的背景颜色。它将用到许多扩展程序平台的组件以作为它们之间关系的一个介绍性演示。

作为开始,我们先创建一个新目录来存放扩展程序的文件。

完整的扩展程序可从此处下载。

创建 manifest

{
 "name": "Getting Started Example",
  "description": "Build an Extension!",
  "version":"1.0",
  "manifest_version":3
}

现在,包含了manifest文件的目录能在开发者模式下作为一个扩展程序被添加。

  1. 在Chrome地址栏中输入 chrome://extensions 以导航到扩展程序管理界面。
    • 也可以这样,点击扩展程序菜单按钮并选择菜单底部的管理扩展程序项。
    • 这样也行,点击Chrome菜单,鼠标悬停在更多工具然后选择扩展程序。
  2. 点击开发者模式旁的开关按钮以开启开发者模式。
  3. 点击加载已解压的扩展程序按钮,选择刚刚创建的扩展程序目录。

https://wd.imgix.net/image/BhuKGJaIeLNPW9ehns59NfwqKxF2/vOu7iPbaapkALed96rzN.png?auto=format&w=741

铛铛!扩展程序已经被成功安装了。因为没有图标在manifest文件中被引用,所以会为扩展程序创建一个默认图标。

添加功能

现在扩展程序已经安装好了,但是它目前不能做任何事因为我们还没告诉它做什么以及什么时候去做。让我们添加一些代码来存储一个背景颜色值以解决这个问题。

在manifest中注册 background script

background script就如其他重要的组件一样,必须在manifest文件中被注册引入。通过在manifest文件中注册引入一个后台脚本,能告诉扩展程序引用哪个文件,以及指定该文件的要干的工作。

{
  "name": "Getting Started Example",
  "description": "Build an Extension!",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  }
}

Chrome现在意识到扩展程序包括一个service worker。当你重新加载扩展,Chrome将扫描指定的文件,以添加新增的指令,例如需要监听的重要事件。

创建background script

扩展程序的功能是一经安装就从持久化的变量中获取背景颜色值。通过在后台脚本中引入监听事件runtime.onInstalled满足该需求。在onInstalled监听器内部,扩展程序使用 storage API 来设定一个数值。这将允许不同扩展程序组件访问与更新该数值。

在扩展的目录中创建一个名为background.js的文件,并添加以下代码。

// background.js

let color = '#3aa757';

chrome.runtime.onInstalled.addListener(() => {
  chrome.storage.sync.set({ color });
  console.log('Default background color set to %cgreen', `color: ${color}`);
});
增加存储权限

包括 storage 的大多数API都必须在manifest文件中的 “permissions”字段下引入,以使扩展程序能够使用它们。

{
  "name": "Getting Started Example",
  "description": "Build an Extension!",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
  "permissions": ["storage"]
}
检查background script

导航回扩展程序管理界面并点击重新加载连接。一个新的选项查看视图出现,并带有一个蓝色链接Service Worker

点击链接以查看后台脚本的控制台日志输出:“默认背景颜色设置为green”

介绍用户界面(user interface)

扩展程序可以拥有许多不同形式的用户界面,本示例将采用一个弹框界面(popup)。在扩展程序目录下创建文件popup.html。此扩展程序使用一个按钮来改变背景颜色。

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="button.css">
  </head>
  <body>
    <button id="changeColor"></button>
  </body>
</html>

就像background script,这个文件必须在manifest中被注册引入以使Chrome在扩展程序的弹框中展示它。为此,向清单中添加一个action对象,并将popup.html设置为该操作的默认弹出窗口。

{
  "name": "Getting Started Example",
  "description": "Build an Extension!",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
  "permissions": ["storage"],
  "action": {
    "default_popup": "popup.html"
  }
}

HTML文件 popup.html 引用了一个外部的CSS文件button.css 。为此在扩展程序目录下添加一个新的文件并以此命名,在文件中添加以下代码:

button {
  height: 30px;
  width: 30px;
  outline: none;
  margin: 10px;
  border: none;
  border-radius: 2px;
}

button.current {
  box-shadow: 0 0 0 2px white,
              0 0 0 4px black;
}

指定工具栏图标的操作也包括在默认图标字段action中。在这里下载images文件夹,解压缩它,并将它放在扩展的目录中。更新manifest ,使扩展知道如何使用图像。

{
  "name": "Getting Started Example",
  "description": "Build an Extension!",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
  "permissions": ["storage"],
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "/images/get_started16.png",
      "32": "/images/get_started32.png",
      "48": "/images/get_started48.png",
      "128": "/images/get_started128.png"
    }
  }
}

扩展程序也会在扩展程序管理界面、权限警告和扩展程序图标中展示这些图片。这些地方的图片指定在manifest文件中的 icons字段设置。

{
  "name": "Getting Started Example",
  "description": "Build an Extension!",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
  "permissions": ["storage"],
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "/images/get_started16.png",
      "32": "/images/get_started32.png",
      "48": "/images/get_started48.png",
      "128": "/images/get_started128.png"
    }
  },
  "icons": {
    "16": "/images/get_started16.png",
    "32": "/images/get_started32.png",
    "48": "/images/get_started48.png",
    "128": "/images/get_started128.png"
  }
}

默认情况下,扩展显示在扩展菜单中(拼图部分)。固定扩展将在工具栏中显示图标。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A30jd3MY-1633856478166)(https://wd.imgix.net/image/BhuKGJaIeLNPW9ehns59NfwqKxF2/GdHNy255kS4hWD5vb1fc.png?auto=format&w=650)]

如果扩展程序在这个阶段被重新加载,它将会包含提供的图标图片而不是采用默认图标,并且点击扩展程序图标将打开一个弹窗,内含一个默认颜色的按钮。

构建弹框UI的最后一步是添加颜色到按钮。在扩展程序目录下创建文件popup.js键入以下代码:

// Initialize button with user's preferred color
// 以用户喜欢的颜色初始化按钮
let changeColor = document.getElementById("changeColor");

chrome.storage.sync.get("color", ({ color }) => {
  changeColor.style.backgroundColor = color;
});

这段代码从popup.html获取按钮,并从存储请求颜色值。然后应用颜色作为按钮的背景。在popup.html中包含一个脚本标签到popup.js

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="button.css">
  </head>
  <body>
    <button id="changeColor"></button>
    <script src="popup.js"></script>
  </body>
</html>

重载扩展程序以查看设置好的绿色按钮。

Layer logic

扩展程序现在拥有一个自定义图标和一个弹框了,并且它根据保存在扩展程序存储中的色值为弹框中的按钮着色。接下来,它需要与用户进一步交互的逻辑。更新popup.js文件,在文件末尾追加以下代码:

// When the button is clicked, inject setPageBackgroundColor into current page
// 当点击按钮,将 setPageBackgroundColor 函数注入到当前页面
changeColor.addEventListener("click", async () => {
  let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });

  chrome.scripting.executeScript({
    target: { tabId: tab.id },
    function: setPageBackgroundColor,
  });
});

// The body of this function will be executed as a content script inside the
// 该函数的主体会作为内容脚本在当前页面内被执行
// current page
function setPageBackgroundColor() {
  chrome.storage.sync.get("color", ({ color }) => {
    document.body.style.backgroundColor = color;
  });
}

更新后的代码为按钮添加了一个点击事件监听器,它会触发一个以编程方式注入的内容脚本。这会将页面的背景颜色变为按钮的颜色。使用以编程方式注入允许用户调用的内容脚本,而不是自动插入不想要的代码到网页。

该清单将需要activeTab权限,以允许扩展临时访问当前页面,并需要脚本权限以使用Scripting API的executeScript方法。

{
  "name": "Getting Started Example",
  ...
  "permissions": ["storage", "activeTab", "scripting"],
  ...
}

至此,扩展程序实现了全部的功能!重载该扩展程序,刷新页面,打开弹框并点击按钮来使页面背景变绿!但是,有些用户或许想要将背景颜色变为另一个不同的颜色。

陷阱:

扩展程序不能在Chrome内部页面注入内容脚本,如 “chrome://extensions”。请务必在一个真实的网页上试用该扩展,如https://google.com。

为用户提供选项

扩展目前只允许用户更改背景为绿色。包括一个选项页面给用户更多的控制扩展的功能,进一步定制他们的浏览体验。首先在名为options.html的目录中创建一个文件,并包含以下代码。

作为开始,在目录下创建文件 options.html 并键入以下代码:

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="button.css">
  </head>
  <body>
    <div id="buttonDiv">
    </div>
    <div>
      <p>Choose a different background color!</p>
    </div>
  </body>
  <script src="options.js"></script>
</html>

然后在manifest文件中引入该选项页面:

{
  "name": "Getting Started Example",
  ...
  "options_page": "options.html"
}

重新加载扩展,右键单击工具栏中的扩展图标,然后选择选项。或者,点击DETAILS,向下滚动细节页面,选择扩展选项。

最后一步是添加选项逻辑。在扩展目录下创建一个名为options.js的文件,代码如下。

let page = document.getElementById("buttonDiv");
let selectedClassName = "current";
const presetButtonColors = ["#3aa757", "#e8453c", "#f9bb2d", "#4688f1"];

// Reacts to a button click by marking the selected button and saving
 对按钮点击事件做出响应,包括标记选中的按钮以及保存选中项
// the selection
function handleButtonClick(event) {
  // Remove styling from the previously selected color
    //  // 移除先前选中颜色的样式
  let current = event.target.parentElement.querySelector(
    `.${selectedClassName}`
  );
  if (current && current !== event.target) {
    current.classList.remove(selectedClassName);
  }

  // Mark the button as selected
     标记按钮为选中状态
  let color = event.target.dataset.color;
  event.target.classList.add(selectedClassName);
  chrome.storage.sync.set({ color });
}

// Add a button to the page for each supplied color
 在页面上为每个提供的颜色添加一个按钮
function constructOptions(buttonColors) {
  chrome.storage.sync.get("color", (data) => {
    let currentColor = data.color;
    // For each color we were provided…
      //  // 对于我们提供的每一种颜色...
    for (let buttonColor of buttonColors) {
      // …create a button with that color…
        //...创建一个对应颜色的按钮...
      let button = document.createElement("button");
      button.dataset.color = buttonColor;
      button.style.backgroundColor = buttonColor;

      // …mark the currently selected color…
           // ...标记当前选中的颜色...
      if (buttonColor === currentColor) {
        button.classList.add(selectedClassName);
      }

      // …and register a listener for when that button is clicked
         // ...注册一个监听按钮点击事件的监听器
      button.addEventListener("click", handleButtonClick);
      page.appendChild(button);
    }
  });
}

// Initialize the page by constructing the color options
// 初始化页面中的颜色选项按钮
constructOptions(presetButtonColors);

提供了四种颜色选项并在选项页生成了对应按钮并监听点击事件。当用户点击一个按钮,它将更新扩展程序存储中的颜色数值。因为扩展程序中所有的编码文件都是从该存储中获取此颜色信息,因此不需要更新其他数值。

进一步学习

Congratulations! 至此目录下已包含一个虽然简单但功能完全的Chrome扩展程序。

下一步该做什么?

/docs/extensions/mv3/overview/)包含了许多信息,有许多关于扩展程序总体架构的详细信息,以及一些开发者想要熟悉的特定概念的说明。

最后更新:2021年7月22日星期四

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐