1. 引言
谈到 Chrome 插件,相信大家都不陌生,我们可以使用 Chrome 插件实现广告拦截、数据抓取、标签管理等功能,这些能力让我们有更好的浏览体验和更高效的办公效率。
Chrome 应用商店中已有各式各样的插件,你当然可以在这里下载你所需要的插件,不过有时你还是需要打造一个更符合自己或团队的插件,以此提升效能,所以学习 Chrome 插件开发是一项极具价值的技能。
Chrome 插件的开发门槛相对较低,只需掌握基础的 HTML、CSS 和 JavaScript 知识即可入门,同时又能快速实现实用的功能。
本文将带你从零开始,了解 Chrome 插件的基本架构和核心 API,并通过几个简单的实例演示,让你体验 Chrome 插件开发流程。
2. 基础概念
2.1 插件构成
Chrome 插件通常由以下几部分组成:
- manifest.json:核心配置文件,指定插件的名称、版本、图标等基础信息,同时根据插件功能在此声明权限,确定要在后台和网页上运行哪些文件。
json
{
"manifest_version": 3, // 3为最新规范
"name": "我的插件",
"version": "1.0",
"description": "插件描述",
"icons": {
"48": "images/icon-48.png",
"128": "images/icon-128.png"
},
"action": { // 浏览器工具栏按钮配置,可选
"default_popup": "popup.html",
"default_icon": "icon.png"
},
"background": { // 后台服务,可选
"service_worker": "background.js"
},
"content_scripts": [{ // 注入网页的脚本,可选
"matches": ["<all_urls>"],
"js": ["content.js"]
}],
"permissions": ["storage", "tabs"], // 需申请的权限,可选
}
- Content Scripts:内容脚本文件,可通过 DOM 操作网页内容。
- Service Worker:用于执行后台任务,在扩展程序的整个生命周期中持续运行。
- Toolbar action(Popup):点击扩展程序图标时弹出的页面。
2.2 核心 API
Chrome 插件开发的核心在于利用浏览器提供的 Extension API,这些 API 让插件能够与浏览器交互,操作标签页、存储数据、拦截网络请求等。
chrome.tabs
- 标签页管理
用途:操作浏览器标签页,如创建、切换、关闭或获取当前活动标签页。
常用方法:
chrome.tabs.create()
- 打开新标签页chrome.tabs.query()
- 查询符合条件的标签页chrome.tabs.update()
- 修改标签页(如跳转 URL)chrome.tabs.remove()
- 关闭标签页chrome.tabs.sendMessage()
- 向指定标签页中的内容脚本发送一条消
示例:
javascript
// 获取当前活动标签页
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
console.log("当前标签页:", tabs[0].url);
});
// 在新标签页打开网址
chrome.tabs.create({ url: "https://example.com" });
chrome.action
- 管理浏览器工具栏按钮
用途:允许开发者控制插件图标的外观、交互行为以及弹出窗口(Popup)。
常用方法:
chrome.action.setIcon()
- 动态修改图标chrome.action.setTitle()
- 修改标题chrome.action.setPopup()
- 动态修改 Popup 页面chrome.action.setBadgeText()
- 设置徽章文字chrome.action.enable()
- 启用工具栏按钮chrome.action.disable()
- 禁用工具栏按钮chrome.action.onClicked.addListener
- 当用户点击工具栏按钮时触发(未设置 Popup 时有效)
示例:
js
// 当插件激活时切换图标
chrome.action.setIcon({
path: isActive ? "icons/active.png" : "icons/inactive.png"
});
// 根据权限状态切换不同弹窗
chrome.action.setPopup({
popup: hasPermission ? "popup.html" : "permission.html"
});
// 设置红色徽章显示数字
chrome.action.setBadgeText({ text: "5" });
// 仅在特定网站启用
chrome.tabs.onActivated.addListener(({ tabId }) => {
chrome.tabs.get(tabId, (tab) => {
const isGmail = tab.url.includes("mail.google.com");
isGmail ? chrome.action.enable(tabId) : chrome.action.disable(tabId);
});
});
chrome.action.onClicked.addListener((tab) => {
console.log("点击了插件图标,当前标签页:", tab.url);
// 可以在这里执行逻辑,如打开新页面
chrome.tabs.create({ url: "https://example.com" });
});
chrome.storage
- 数据存储
用途:存储插件数据,当用户清除浏览数据时,扩展程序存储空间不会被清除。
两种存储方式:
chrome.storage.local
- 本地存储(仅当前设备)chrome.storage.sync
- 同步存储(跨设备,需用户登录 Chrome)
示例:
js
// 存储数据
chrome.storage.local.set({ key: "value" }, () => {
console.log("数据已保存");
});
// 读取数据
chrome.storage.local.get(["key"], (result) => {
console.log("读取到的数据:", result.key);
});
chrome.runtime
- 插件生命周期与通信
用途:管理插件运行环境,支持后台脚本与内容脚本通信。
常用方法:
chrome.runtime.sendMessage()
- 发送消息(用于不同脚本间通信)chrome.runtime.onMessage.addListener()
- 监听消息chrome.runtime.getURL()
- 获取插件内资源的绝对路径chrome.runtime.onInstalled()
- 安装或更新插件触发
示例:
js
// 内容脚本(content.js)发送消息
chrome.runtime.sendMessage({ action: "greet", data: "Hello from content script!" });
// 后台脚本(background.js)接收消息
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "greet") {
console.log("收到消息:", request.data);
sendResponse({ reply: "Message received!" });
}
});
// background.js (Service Worker)
chrome.runtime.onInstalled.addListener((details) => {
if (details.reason === "install") {
console.log("首次安装");
// 初始化默认数据
chrome.storage.local.set({ config: defaultSettings });
}
else if (details.reason === "update") {
console.log(`从版本 ${details.previousVersion} 更新`);
// 执行数据迁移
}
});
chrome.webRequest
- 网络请求拦截与修改
用途:监控或修改 HTTP 请求(需在 manifest.json
声明权限)。
适用场景:
- 广告拦截
- 请求重定向
- 修改请求头
示例(拦截请求):
js
// 在 manifest.json 中添加权限:
// "permissions": ["webRequest", "webRequestBlocking", "<all_urls>"]
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
return {cancel: details.url.indexOf("://www.evil.com/") != -1};
},
{ urls: ["<all_urls>"] },
["blocking"]
);
chrome.contextMenus
- 右键菜单定制
用途:在浏览器右键菜单中添加自定义选项。
示例:
js
// 在 manifest.json 中添加权限:
// "permissions": ["contextMenus"]
chrome.contextMenus.create({
id: "search-google",
title: "Search Google for '%s'", // %s 会替换成选中的文本
contexts: ["selection"], // 仅在选择文本时显示
});
// 监听菜单点击事件
chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === "search-google") {
const query = encodeURIComponent(info.selectionText);
chrome.tabs.create({ url: `https://www.google.com/search?q=${query}` });
}
});
chrome.notifications
- 桌面通知
用途:向用户发送系统级通知(需权限)。
示例:
js
// 在 manifest.json 中添加权限:
// "permissions": ["notifications"]
chrome.notifications.create("reminder", {
type: "basic",
iconUrl: "icon.png",
title: "提醒",
message: "您有一条新消息!",
});
3. 插件开发
接下来让我们通过实例演示来看看插件如何开发。
3.1 Hello World
按学习编程惯例,我们先实现一个 Hello World 功能,让用户点击插件图标时,弹出一个 Hello World 界面。
要想实现此功能,插件只需创建 manifest.json 和 popup,先如下创建对应的插件项目结构:
bash
HelloWolrd
├── images
│ ├── icon-16.png
│ ├── icon-32.png
│ ├── icon-48.png
│ └── icon-128.png
├── popup
│ ├── popup.css
│ └── popup.html
└── manifest.json
图片可以直接去 iconfont 上下载即可,我们先来看下 manifest.json。
json
{
"manifest_version": 3,
"name": "Hello Extensions",
"description": "Base Level Extension",
"version": "1.0",
"icons": {
"16": "images/icon-16.png",
"32": "images/icon-32.png",
"48": "images/icon-48.png",
"128": "images/icon-128.png"
},
"action": {
"default_popup": "popup/popup.html"
},
}
manifest.json 中有 5 个基本配置项(插件规范版本、插件名称、插件描述、插件版本、插件图标)和工具栏按钮配置(action
)。
在工具栏按钮配置中使用 default_popup
指定了点击按钮后弹窗要展示的内容。弹窗的内容就是 html、css、javascript 组成,在本示例中我们简单实现下。
popup.html 内容如下:
html
<html>
<head>
<link rel="stylesheet" href="./popup.css">
</head>
<body>
<h1>Hello World</h1>
<p class="blue">blue text</p>
</body>
</html>
popup.css 内容如下:
css
body {
width: 150px;
}
.blue {
color: #1677ff;
}
至此我们就完成了一个 Hello World 的插件编写,接着我们要在浏览器上加载此插件,并查看效果。
可如下加载本地插件:
- 在浏览器新标签页中输入
chrome://extensions
,或者通过工具栏打开。 - 点击开发者模式旁边的切换开关,即可启用开发者模式。
- 点击加载已解压缩的文件按钮,然后选择扩展程序目录(本示例中即 HelloWolrd 文件夹)。

安装完插件,我们就可以在工具栏点击插件,查看效果。
3.2 运行内容脚本
内容脚本可以静态声明、动态声明或以编程方式注入,本示例将以静态声明方式注入,其他方式可以查看内容脚本文档。
首先创建项目结构:
bash
ContentScript
├── images
│ ├── icon-16.png
│ ├── icon-32.png
│ ├── icon-64.png
│ └── icon-128.png
├── content.js
└── manifest.json
manifest.json 如下:
json
{
"name": "Hello Content Script",
"description": "Base Level Extension",
"version": "1.0",
"manifest_version": 3,
"icons": {
"16": "images/icon-16.png",
"32": "images/icon-32.png",
"48": "images/icon-48.png",
"128": "images/icon-128.png"
},
"content_scripts": [
{
"js": ["content.js"],
"matches": ["<all_urls>"]
}
]
}
内容脚本的注入通过 content_scripts
进行,在这个字段中,我们指定了要执行的脚本和哪些网页会执行该脚本,<all_urls>
代表匹配所有网址。
接下来看 content.js 内容:
js
const div = document.createElement('div')
div.innerText = '插件内容'
document.body.prepend(div)
该脚本内容会在 body 中插入一个文本内容,加载插件后刷新下页面即可看到页面多了个"插件内容"的文字。

3.3 使用 Service Worker 处理事件
我们可以用 Service Worker 来监听浏览器标签更新、监听插件安装或更新、定时通知提醒、广告拦截、与弹出窗口或内容脚本通信等等。
本示例中我们使用 Service Worker 往内容脚本发消息,消息内容为当前 tab 的标题。
项目结构如下:
bash
ServiceWorker
├── images
│ ├── icon-16.png
│ ├── icon-32.png
│ ├── icon-64.png
│ └── icon-128.png
├── content.js
├── manifest.json
└── service-worker.js
相比于上个示例,manifest.json 中多了两个字段:
json
{
"name": "Hello ServiceWorker",
"description": "Base Level Extension",
"version": "1.0",
"manifest_version": 3,
"icons": {
"16": "images/icon-16.png",
"32": "images/icon-32.png",
"48": "images/icon-48.png",
"128": "images/icon-128.png"
},
"permissions": ["tabs"],
"content_scripts": [
{
"js": ["content.js"],
"matches": ["<all_urls>"]
}
],
"background": {
"service_worker": "service-worker.js"
}
}
使用 background.service_worker
字段指定后台运行的脚本。因为我们要读取标签页的标题,所以我们需要加个权限说明 "permissions": ["tabs"]
。
接着 service-worker 的代码如下:
js
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete') {
chrome.tabs.sendMessage(tab.id, {
data: tab.title,
})
}
});
chrome.tabs.onUpdated
的作用是监听标签页加载完成或更新,入参的回调函数中,我们控制当页面加载完成时,后台脚本会往 tabs
发送一个消息,消息内容为标签页面标题。
js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
const div = document.createElement('div')
div.innerText = request.data
document.body.prepend(div)
})
内容脚本使用 chrome.runtime.onMessage
来监听消息,收到消息后输出到页面,效果如下:
3.4 替换页面
你可能有使用过一些插件来替换浏览器的默认标签页,本示例将带你实现这个功能。
先看下项目结构:
bash
NewTab
├── images
│ ├── icon-16.png
│ ├── icon-32.png
│ ├── icon-64.png
│ └── icon-128.png
├── myPage.html
└── manifest.json
项目结构中主要是 manifest.json 和 myPage.html,我们需要在 manifest.json 中定义使用 myPage.html 替换默认标签页。
js
{
"name": "Hello NewTab",
"description": "Base Level Extension",
"version": "1.0",
"manifest_version": 3,
"icons": {
"16": "images/icon-16.png",
"32": "images/icon-32.png",
"48": "images/icon-48.png",
"128": "images/icon-128.png"
},
"chrome_url_overrides" : {
"newtab": "myPage.html"
}
}
可以看到 manifest.json 中定义了一个 chrome_url_overrides
字段,里面指定了 newtab
要加载 myPage.html
。
除了覆盖默认标签页,你还可以覆盖历史记录和书签页面,"history": "myPage.html"
、"bookmarks": "myPage.html"
。
接下来就是 myPage.html 内容:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>我的标签页</p>
</body>
</html>
加载插件后,打开一个新的标签页,效果如下:
4. 插件调试
4.1 popup 调试
插件工具栏弹窗内容的可以通过右键插件图标,选择"审查弹出内容"即可打开 Chrome 调试工具。

4.2 Service Worker 调试
Service Worker 的调试在插件管理界面,如果你的插件有后台脚本,可以点击插件的 "检查视图 Service Worker" 打开 Chrome 调试工具。
4.3 content-script 调试
内容脚本的调试需要在当前标签页打开 Chrome 开发者工具,在"源代码/来源"页签的左侧中找到"内容脚本",选择你插件的内容脚本即可开始调试。

5. 总结
至此我们已经完成了 Chrome 插件开发的入门,更多内容可查阅官方文档。
如果你有好的想法,可以尝试自己开发一款 Chrome 插件,在实现自己想法的同时,或许可以通过插件获取收益。