本教程按照官方文档给的栗子进行了本地化改良。
官方文档地址:https://developer.chrome.com/docs/extensions/mv3/getstarted/#next-steps
教程里使用的文档链接均为官方链接,所以必须使用魔法上网才能看到。

插件的功能为:修改指定网站的背景颜色。

完整的代码可在这里下载:下载地址

创建配置文件

首先需要一个插件的配置文件,每一个chrome的插件都需要有一个manifest.json配置文件,因此你可以在电脑里新建一个目录,然后在此目录里新建一个manifest.json并写入以下代码:

{
  "name": "myTestPlug",
  "description": "我的第一个chrome插件",
  "version": "1.0",
  "manifest_version": 3
}
  • name:插件名称
  • description:插件介绍
  • version:插件版本
  • manifest_version:使用的版本语言,目前最新的版本是v3

这个配置文件的具体详细文档地址:https://developer.chrome.com/docs/extensions/mv3/manifest/


加载插件

在开发模式下,需要打开chrome的开发者模式才可以测试自己写的插件。
打开的方法为:

  1. chrome浏览器的地址栏输入:chrome://extensions/
  2. 在右上角会找到一个开关:“开发者模式”;
  3. 打开开关后,会发现在插件的页面内出现三个按钮:“加载已解压的扩展程序”、“打包扩展程序”、“更新”;
  4. 点击“加载已解压的扩展程序”,选择自己刚刚的插件目录即可成功加载自己的插件了;

如图,你会看到刚才的插件已经被创建。因为我们没有在配置文件里定义插件的图标,因此chrome会赋予一个默认图标。


在配置文件中注册脚本

我们首先需要注册一个主js文件,可以把它看作为web应用与chrome浏览器之间的“代理服务器”,它可以监听、修改、拦截web应用的资源和请求。
编辑刚才的manifest.json配置文件,并在之前的基础上增加脚本,完整代码如下:

{
  "name": "myTestPlug",
  "description": "我的第一个chrome插件",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  }
}

其中background指的是chrome浏览器的后台,而service_worker就是Google推行的渐进式网页应用(PWA)的理念之一。
这里需要注意的是,background.js文件必须要放在插件的根目录下。

关于service_worker的文档地址:https://developer.chrome.com/docs/extensions/mv3/service_workers/


新建一个background.js

此时我们需要创建一个颜色变量,并且要使插件的其他页面能读取并修改这个变量,因此我们在插件的根目录下新建一个background.js文件,并且写入以下代码:

// background.js

// 定义颜色
let color = '#3aa757';

// 首次安装插件、插件更新、chrome浏览器更新时触发
chrome.runtime.onInstalled.addListener(() => {
  chrome.storage.sync.set({ color });
  console.log('插件默认颜色为: %c #3aa757', `color: ${color}`);
});

在以上代码里,我们首先使用到了chrome浏览器的一个生命周期的钩子onInstalled,这个钩子在首次安装插件、插件更新、chrome浏览器更新时触发,关于chrome浏览器的其他生命周期文档地址:https://developer.chrome.com/docs/extensions/reference/runtime/#event

其次我们使用到了chrome浏览器的一个存储API:chrome.storage,这个API可以满足插件一定的存储需求,并且可以在插件的其他页面内随时调取使用并修改,其相关的文档地址为:https://developer.chrome.com/docs/extensions/reference/storage/

在chrome插件开发里,大部分的API都需要在manifest.json配置文件先注册,再使用,因此我们需要继续编辑manifest.json,完整代码如下:

{
  "name": "myTestPlug",
  "description": "我的第一个chrome插件",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
  "permissions": ["storage"]
}

检查刚才的代码

在以上操作完成后,我们可以在插件的页面里调取控制台来检查一下刚才的代码了,我们回到扩展程序的页面,点击自己插件的“刷新”按钮,然后点击“查看视图 Service Worker”,即可打开插件的控制台,并且查看到刚才打印的文字。


制作chrome插件的弹出窗口

接下来我们需要制作一个用户界面,也就是每个chrome插件在点击时都会弹出的那个窗口。因此我们需要先创建一个popup.html文件,这便是弹出窗口的html页面,代码如下:

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="popup.css">
  </head>
  <body>
    <button id="changeColor" class="color-btn"></button>
  </body>
</html>

我们在head里引用了popup.css文件,因此也需要同时创建一个popup.css文件,代码如下:

.color-btn {
  height: 30px;
  width: 30px;
  outline: none;
  margin: 10px;
  border: none;
  border-radius: 2px;
  cursor: pointer;
}

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

在配置文件里注册弹出窗口

和注册background.js一样,弹出窗口也必须要在manifest.json配置文件完成注册:

{
  "name": "myTestPlug",
  "description": "我的第一个chrome插件",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
  "permissions": ["storage"],
  "action": {
    "default_popup": "popup.html"
  }
}

在这里,我们在actionAPI的default_popup中注册了刚才的弹出窗口页面,actionAPI中还可以注册插件的图标,具体的文档链接为:https://developer.chrome.com/docs/extensions/reference/action/
图标的使用会在教程结尾处讲解。


查看弹出窗口

在完成了弹出窗口注册后,我们再次回到chrome的插件管理页面,在点击刷新后,我们将自己的插件固定在浏览器的插件工具栏中:

同时点击一下自己的插件,就会发现刚才制作好的弹出窗口:

在这里我们也可以用刚才设置好的绿色为这个按钮添加一个颜色,在这里我们需要创建一个popup.js,完整代码如下:

// popup.js

// 获取按钮实例
let changeColor = document.getElementById('changeColor');

// 从chrome插件的存储里读取color变量并修改按钮颜色
chrome.storage.sync.get('color', ({ color }) => {
  changeColor.style.backgroundColor = color;
});

同时我们也需要在popup.html中引用这个js,打开popup.html后,修改代码如下:

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

再次回到chrome插件管理页面,重新加载一遍插件后即可看到绿色按钮,或者不用刷新,稍微等段时间再次点击插件也可以。


添加逻辑

接下来我们开始实现点击按钮改变目标页面背景色的功能了,因此我们需要用到两个chrome浏览器提供的API权限:
第一个是activeTab权限,用于使用chrome.tabsAPI让插件有权限访问当前打开的标签页,对应的详细文档地址:https://developer.chrome.com/docs/extensions/reference/tabs/
第二个是scripting权限,用于使用chrome.scriptingAPI将JavaScript 和 CSS 注入网站,对应其完整的文档为:https://developer.chrome.com/docs/extensions/reference/scripting/

storage权限一样,我们也需要去manifest.json配置文件完成注册,打开manifest.json,完整的代码如下:

{
  "name": "myTestPlug",
  "description": "我的第一个chrome插件",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
  "permissions": ["storage", "activeTab", "scripting"],
  "action": {
    "default_popup": "popup.html"
  }
}

注册后,我们回到popup.js,完成对按钮的逻辑操作,完整代码如下:

// popup.js

// 获取按钮实例
let changeColor = document.getElementById('changeColor');

// 从chrome插件的存储里读取color变量并修改按钮颜色
chrome.storage.sync.get('color', ({ color }) => {
  changeColor.style.backgroundColor = color;
});

// 点击按钮
changeColor.addEventListener('click', async() => {
  // 获取当前打开的标签页面
  // 因为需要先准确地获取当前的页面才能注入js,所以这里需要使用同步函数,await
  let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });

  // 向目标页面里注入js方法
  chrome.scripting.executeScript({
    target: { tabId: tab.id },
    function: setPageBackgroundColor
  });
});

// 注入的方法
function setPageBackgroundColor() {
  // 从chrome插件的存储里读取color变量并修改当前页面的body背景色
  chrome.storage.sync.get("color", ({ color }) => {
    document.body.style.backgroundColor = color;
  });
};

调试代码方法:右键点击小窗口的空白处,点击“检查”,即可打开控制台调试代码。

到此为止,一个简单的chrome浏览器插件已经完成了,可以随便打开一个网站点击绿色的小按钮尝试一下。


增加设置页面

实现了第一个小Demo后,用户就会提出新的需求,比如不满足只有一种颜色的切换,应该有一个配置页面来由用户决定使用哪些颜色。

需求,永无止境。

因此我们需要增加一个插件设置页面,与弹出窗口popup.html一样,插件的设置页面也需要在manifest.json配置文件注册一下,我们打开manifest.json,完整代码如下:

{
  "name": "myTestPlug",
  "description": "我的第一个chrome插件",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
  "permissions": ["storage", "activeTab", "scripting"],
  "action": {
    "default_popup": "popup.html"
  },
  "options_page": "options.html"
}

同时,我们也需要创建好一个对应的options.html页面,完整代码如下:

<!DOCTYPE html>
<html>
  <head>
    <!-- 此处我们可以沿用popup.html的页面样式 -->
    <link rel="stylesheet" href="popup.css">
  </head>
  <body>
    <div id="colorBtns"></div>
    <script src="options.js"></script>
  </body>
</html>

此时我们需要再次回到chrome插件管理页面,重新加载一遍插件,然后右键点击我们的插件,就会发现出现了“选项”这一选项。


实现选项页面的逻辑

最后,我们需要实现一下选项的逻辑,创建options.js后,增加以下代码:

// options.js

let colorBtns = document.getElementById("colorBtns"); // 按钮实例
let currentClassName = 'current'; // 当前选择的颜色

const colorList = ["#3aa757", "#e8453c", "#f9bb2d", "#4688f1"];

/**
 * 设置颜色按钮
 * 
 * @param {Array} colorList 颜色列表
 * 
*/
function setColorBtns(colorList) {
  
  // 获取当前存储的颜色
  chrome.storage.sync.get('color', (data) => {

    let currentColor = data.color; // 当前已选中的颜色
    
    // 遍历颜色列表并创建按钮
    colorList.map((item) => {
      let button = document.createElement('button'); // 创建按钮
      button.dataset.color = item; // 为每个按钮设置颜色变量, 存储在dataset中, 为点击事件作参数准备
      button.style.backgroundColor = item; // 设置按钮颜色样式
      button.classList.add('color-btn'); // 设置按钮样式 - popup.css

      // 设置当前已选中的按钮
      if (currentColor === item) {
        button.classList.add(currentClassName);
      };

      // 对按钮绑定点击事件
      button.addEventListener('click', handleButtonClick);

      // 将按钮写入页面
      colorBtns.appendChild(button);

    });

  });

};

/**
 * 按钮点击事件
 * 
 * @param {Object} event 按钮本身
 * 
*/
function handleButtonClick(event) {
  
  // 删除其他按钮的选中样式
  let current = event.target.parentElement.querySelector(`.${currentClassName}`); // 从上一级dom结构里获取当前已选中的按钮
  if (current && current !== event.target) {
    // 删除按钮的选中样式
    current.classList.remove(currentClassName);
  };

  // 给当前按钮增加选中样式
  event.target.classList.add(currentClassName);
  
  // 修改当前chrome插件中存储的颜色
  let color = event.target.dataset.color; // 获取按钮中的dataset参数
  chrome.storage.sync.set({ color });
};

// 执行
// 批量添加按钮
setColorBtns(colorList);

测试

右键点击插件,选择“选项”后,会打开options.html页面,并且实现了4种颜色的按钮,每点击按钮后,都会影响插件弹出窗口的按钮本身的颜色及功能。


关于图标

chrome插件的图标分为两种:
第一种是用于在工具栏中显示,对应的注册地址在manifest.json配置文件中的actiondefault_icon里;
第二种则用于除了工具栏以外的其他地方,同样也在manifest.json配置文件中,icons的选项里。
关于本插件,加完图标的完整代码是:

{
  "name": "myTestPlug",
  "description": "我的第一个chrome插件",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  },
  "permissions": ["storage", "activeTab", "scripting"],
  "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"
  }
  "options_page": "options.html"
}

将你的图标放入images文件夹内即可。