这个周末我创建了一个 Chrome 扩展程序,因为我发现自己一遍遍地执行相同的任务,并且想要将其自动化。此外,我是一个宅在家里躲避疫情的书呆子,所以我把积攒的能量都用在了构建东西上。这些年来我创建了一些 Chrome 扩展程序,希望这篇文章也能帮助你入门。让我们开始吧!
创建清单文件
第一步是在项目文件夹中创建一个 manifest.json
文件。它的作用类似于 package.json
,它为 Chrome 网上应用店提供有关项目的重要信息,包括名称、版本、所需的权限等。以下是一个示例
{
"manifest_version": 2,
"name": "Sample Name",
"version": "1.0.0",
"description": "This is a sample description",
"short_name": "Short Sample Name",
"permissions": ["activeTab", "declarativeContent", "storage", "<all_urls>"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"css": ["background.css"],
"js": ["background.js"]
}
],
"browser_action": {
"default_title": "Does a thing when you do a thing",
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"32": "icons/icon32.png"
}
}
}
您可能会注意到一些内容 - 首先:名称和描述可以是您想要的任何内容。
权限取决于扩展程序需要执行的操作。在本例中,我们有 ["activeTab", "declarativeContent", "storage", "<all_urls>"]
,因为此特定扩展程序需要有关活动选项卡的信息,需要更改页面内容,需要访问 localStorage
,并且需要在所有网站上处于活动状态。如果它只需要在一个网站上处于活动状态,我们可以删除该数组的最后一个索引。
可以在 Chrome 的扩展程序文档中找到所有权限及其含义的列表 Chrome 扩展程序文档。
"content_scripts": [
{
"matches": ["<all_urls>"],
"css": ["background.css"],
"js": ["background.js"]
}
],
content_scripts
部分设置扩展程序应处于活动状态的站点。如果您想要一个单独的站点,例如 Twitter,则应输入 ["https://twitter.com/*"]
。CSS 和 JavaScript 文件是扩展程序所需的一切。例如,我的 高效 Twitter 扩展程序 使用这些文件来覆盖 Twitter 的默认外观。
"browser_action": {
"default_title": "Does a thing when you do a thing",
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"32": "icons/icon32.png"
}
}
browser_action
中的一些内容也是可选的。例如,如果扩展程序不需要弹出窗口来实现其功能,则可以删除 default_title
和 default_popup
。在这种情况下,只需要扩展程序的图标。如果扩展程序仅在某些站点上有效,则 Chrome 会在它处于非活动状态时将其图标灰显。
调试
清单文件、CSS 和 JavaScript 文件准备就绪后,请从浏览器的地址栏访问 chrome://extensions/
并启用开发者模式。这将激活“加载未打包”按钮以添加扩展程序文件。还可以切换开发版本扩展程序是否处于活动状态。

我强烈建议此时开始一个 GitHub 存储库来对文件进行版本控制。这是保存工作的好方法。
更新扩展程序时,需要从此界面重新加载它。屏幕上会显示一个小的刷新图标。此外,如果扩展程序在开发过程中出现任何错误,它也会在此处显示一个带有堆栈跟踪和更多信息的错误按钮。
弹出窗口功能
如果扩展程序需要使用从扩展程序图标弹出的弹出窗口,那么幸运的是,这非常简单。在清单文件中使用 browser_action
指定文件名称后,可以使用您喜欢的任何 HTML 和 CSS 构建页面,包括图像(我倾向于使用内联 SVG)。
我们可能希望向弹出窗口添加一些功能。这可能需要一些 JavaScript,因此请确保在清单文件中指定了 JavaScript 文件,并在您的弹出窗口文件中也链接了它,如下所示:<script src="background.js"></script>
在该文件中,首先创建功能,我们将能够访问弹出窗口 DOM,如下所示
document.addEventListener("DOMContentLoaded", () => {
var button = document.getElementById("submit")
button.addEventListener("click", (e) => {
console.log(e)
})
})
如果我们在 popup.html
文件中创建一个按钮,为其分配一个名为 submit
的 ID,然后返回一个控制台日志,您可能会注意到实际上没有在控制台中记录任何内容。这是因为我们处于不同的上下文中,这意味着我们需要右键单击弹出窗口并打开一组不同的 DevTools。

我们现在可以访问日志记录和调试了!但请记住,如果在 localStorage
中设置了任何内容,则它将仅存在于扩展程序的 DevTools localStorage
中;而不是用户的浏览器 localStorage
中。(我第一次尝试时就遇到了这个问题!)
在扩展程序外部运行脚本
这都很好,但是假设我们想要运行一个可以访问当前选项卡信息的脚本?以下是如何执行此操作的几种方法。我通常会在 DOMContentLoaded
事件侦听器内部调用一个单独的函数
示例 1:激活文件
function exampleFunction() {
chrome.tabs.executeScript(() => {
chrome.tabs.executeScript({ file: "content.js" })
})
}
示例 2:执行少量代码
如果只有少量代码需要运行,这种方法非常不错。但是,由于它需要将所有内容作为字符串或模板字面量传递,因此很快就会变得难以处理。
function exampleFunction() {
chrome.tabs.executeScript({
code: `console.log(‘hi there’)`
})
}
示例 3:激活文件并传递参数
请记住,扩展程序和选项卡在不同的上下文中运行。这使得在它们之间传递参数变得并非易事。我们在这里要做的是嵌套前两个示例,将一些代码传递到第二个文件中。我将所有需要的内容存储在一个选项中,但我们需要将对象字符串化才能使其正常工作。
function exampleFunction(options) {
chrome.tabs.executeScript(
{ code: "var options = " + JSON.stringify(options) },
function() {
chrome.tabs.executeScript({ file: "content.js" })
}
)
}
图标
即使清单文件只定义了两个图标,我们还需要另外两个才能正式将扩展程序提交到 Chrome 网上应用店:一个 128px 正方形的图标,以及我称为 icon128_proper.png
的图标,它也是 128px,但在图像边缘和图标之间有一点填充。
请记住,无论使用哪个图标,都需要在浏览器的亮模式和暗模式下看起来都很好。我通常在 Noun Project 上找到我的图标。
提交到 Chrome 网上应用店
现在,我们可以前往 Chrome 网上应用店开发者控制台 提交扩展程序!单击“新建项目”按钮,然后将压缩的项目文件拖放到上传器中。

然后,Chrome 会询问一些有关扩展程序的问题,并请求有关扩展程序中请求的权限以及为何需要这些权限的信息。友情提示:请求 “activeTab”
或 “tabs”
权限需要更长时间的审查,以确保代码没有执行任何滥用行为。
就是这样!这应该可以让你开始构建 Chrome 浏览器扩展程序!🎉
我使用 extensionizr.com
这很酷!
谢谢!我最近也开发了一个扩展程序,我不得不浏览非常旧的教程和文档才能将这些信息整合在一起。刚刚收藏了这个。<3
从未想过通过浏览器扩展程序来自动化某些操作,因此感谢您提供这个想法和指南。
我能够构建一个扩展程序来解析来自我们 API 的 JSON 响应,这也是我以前从未做过的。
你在清单的 content scripts 部分提到了 background.js,扩展运行时中还有一个名为 background scripts 的上下文,确保不要将这两个混淆。
嘿,Sarah,很棒的内容!感谢你写下这些。关于编写扩展程序的内容不够多,而且文档不太好,有时甚至令人困惑。
这里使用
executeScript
的目的是什么?你的 content scripts 应该默认已经可以访问 DOM,因为它们就像页面上的任何其他脚本标签一样加载,并且 URL 与你在清单中列出的网站匹配。我同意上面那位人士的观点,将你的 content script 文件命名为
background.js
有点令人困惑,因为 content scripts 在页面上运行的角色与在清单中单独声明并在扩展程序启用时始终在后台线程上运行的 background scripts 之间存在很大差异,但它们无法访问选项卡的内容(用于监听 post 消息、维护跨选项卡/页面的状态、处理安装/更新后的事件等)。希望这有帮助,再次感谢,我喜欢你的内容,并感谢你总是抽出时间写作和教育大家!
你真的会使用 chrome.tabs.executeScript 上传你的扩展程序吗?Chrome 网上应用商店批准了吗?我表示怀疑。
chrome.tabs.executeScript 是一个严重的安全性漏洞。我认为 CWS 会阻止此类扩展程序。
如果要在你当前的选项卡页面上下文中运行脚本,则应向“content script”发送 sendMessage,然后在那里处理该消息。
已获批准。也有一种比这更有建设性的方式来分享知识。
这非常有帮助!刚刚完成了我的第一个扩展程序的提交。
你好,Sarah,非常感谢你提供的精彩内容。我一直按照你的帖子来创建我的扩展程序,但是当我尝试以你所述的方式注入 js 文件时,出现了以下错误
“Uncaught TypeError: Error in invocation of tabs.executeScript(optional integer tabId, extensionTypes.InjectDetails details, optional function callback): No matching signature.”
我基本上使用了与你相同的方法来添加 js 文件,但显然“executeScript”语句存在问题
$(document).ready(() => {
var button = document.getElementById(“submit”);
function exampleFunction() {
chrome.tabs.executeScript(() => {
chrome.tabs.executeScript({ file: “content.js” });
});
}
$(button).click((e) => {
exampleFunction();
});
});
很高兴找到这个!我不完全确定是什么,但我似乎总是难以处理清单文件和分配正确的权限,所以感谢你的澄清!
出于好奇,你对像 Extensionizr.com 或 ChromeExtensionKit.com 这样的工具有什么看法,它们可以帮助进行很多设置?
我认为从技术角度来看,商店中的 GoodPlan Notes 是一个非常好的例子。
设置 content_scripts 不会在与 matches 数组不匹配的网站上禁用扩展程序。
我发现的一种使其工作的方法是
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([{
conditions: [new chrome.declarativeContent.PageStateMatcher({
pageUrl: {hostEquals: ‘domain.com’},
})
],
actions: [new chrome.declarativeContent.ShowPageAction()]
}]);
});
问题
我们是否非常确定在这个示例中需要嵌套的
executeScript
?各位,能否提供一个关于清单 v3 的新教程?目前我正在对着墙猛敲脑袋,因为可用的清单 v3 资源太少了。