谷歌插件开发入门示例
3047字约10分钟
2024-11-13
扩展由不同但有凝聚力的组件组成。组件可以包括后台脚本(background scripts)、内容脚本(content scripts)、选项页面(options page)、UI 元素(UI elements)和各种逻辑文件。扩展组件是使用 Web 开发技术创建的:HTML、CSS 和 JavaScript。扩展的组件将取决于其功能,并且可能不需要每个选项。
本教程将构建一个扩展,允许用户更改当前聚焦页面的背景颜色。它将使用许多扩展平台的组件来介绍它们之间的关系。
首先,创建一个新目录来保存扩展的文件。
创建 manifest
扩展从它们的清单开始。创建一个名为 manifest.json 的文件并包含以下代码。
{
"name": "Getting Started Example",
"description": "Build an Extension!",
"version": "1.0",
"manifest_version": 3
}
保存清单文件的目录可以在当前状态下作为开发人员模式的扩展添加。
- 通过导航到打开扩展管理页面 chrome://extensions
或者,通过单击扩展菜单按钮并选择菜单底部的管理扩展来打开此页面。
或者,通过单击 Chrome 菜单打开此页面,将鼠标悬停在更多工具上,然后选择扩展程序
通过单击开发人员模式旁边的切换开关启用开发人员模式。
通过单击开发人员模式旁边的切换开关启用开发人员模式。
在清单中注册后台脚本
与许多其他重要组件一样,后台脚本必须在清单中注册。在清单中注册后台脚本告诉扩展要引用哪个文件,以及该文件的行为方式。
{
"name": "Getting Started Example",
"description": "Build an Extension!",
"version": "1.0",
"manifest_version": 3,
// 注册后台脚本
"background": {
"service_worker": "background.js"
}
}
Chrome 现在知道该扩展程序包含一个 Service Worker。当您重新加载扩展程序时,Chrome 会扫描指定文件以获取其他说明,例如它需要侦听的重要事件。
创建文件目录层级
该扩展程序要创建的文件目录层级如下:
├─ manifest.json
├─ background.js
├─ popup.html
├─ popup.js
├─ button.css
├─ options.html
├─ options.js
└─ images
├─ icon-128.png
├─ icon-48.png
└─ icon-16.png
创建后台脚本
一旦安装,此扩展将需要来自持久变量的信息。首先在后台脚本中包含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}`);
});
添加存储权限
大多数 API,包括storage API
,必须在清单 manifest.json
中的 permissions
字段下注册,扩展程序才能使用它们。
{
"name": "Getting Started Example",
"description": "Build an Extension!",
"version": "1.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
// 开启权限
"permissions": ["storage"]
}
检查后台脚本
导航回扩展管理页面,然后单击重新加载链接。一个新字段 Inspect views
可用,带有蓝色链接 service worker
。
点击链接可开启控制台查看后台脚本的控制台日志,“默认背景颜色设置为绿色”。
引入用户界面
扩展可以有多种形式的user interface
;这将使用一个popup
。创建一个名为 popup.html
的文件并将其添加到扩展的目录中。此扩展程序使用按钮来更改背景颜色。
<!-- popup.html -->
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="button.css" />
</head>
<body>
<button id="changeColor"></button>
</body>
</html>
与后台脚本一样,此文件必须在清单manifest.json
中声明,以便 Chrome 在扩展程序的弹出窗口中显示它。为此,请向清单添加一个action
对象并将 popup.html
设置为操作的 default_popup
。
{
"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 引用了一个名为 button.css
的外部 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;
}
工具栏图标的名称也包含在 default_icons
字段中的 action
下。在此处下载图像文件夹,解压缩,并将其放置在扩展程序的目录中。更新清单manifest.json
,以便扩展程序知道如何使用图像。
{
"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.json
中的 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"
}
}
默认情况下,扩展出现在扩展菜单(拼图)中。固定扩展程序将在工具栏中显示图标。
如果在此阶段重新加载扩展程序,它将包含提供的图标而不是默认占位符,单击该操作将打开一个弹出窗口,其中显示一个显示默认颜色的按钮。
弹出 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>
重新加载扩展程序以查看绿色按钮。
层逻辑
该扩展现在有一个自定义图标和一个弹出窗口,它根据保存到扩展存储中的值为弹出按钮着色。接下来,它需要用于进一步用户交互的逻辑。通过将以下内容添加到文件末尾来更新 popup.js
。
// 单击按钮时,将 setPageBackgroundColor 注入当前页面
changeColor.addEventListener("click", async () => {
let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
chrome.scripting.executeScript({
target: { tabId: tab.id },
function: setPageBackgroundColor,
});
});
// 此函数的主体将作为内容脚本执行
// 当前页面
function setPageBackgroundColor() {
chrome.storage.sync.get("color", ({ color }) => {
document.body.style.backgroundColor = color;
});
}
更新后的代码向按钮添加了一个单击事件侦听器,这会触发以编程方式注入的内容脚本。这将使页面的背景颜色与按钮的颜色相同。这会将页面的背景颜色变为与按钮相同的颜色。使用编程注入允许用户调用内容脚本,而不是自动将不需要的代码插入网页。
清单manifest.json
将需要 activeTab
权限以允许扩展临时访问当前页面,以及 scripting
权限以使用脚本 API 的 executeScript
方法。
{
"name": "Getting Started Example",
...
"permissions": ["storage", "activeTab", "scripting"],
...
}
该扩展现在功能齐全!重新加载扩展程序,刷新此页面,打开弹出窗口并单击按钮将其变为绿色!但是,某些用户可能希望将背景更改为不同的颜色。
注意
扩展程序无法在 Chrome 内部页面上注入内容脚本,例如“chrome://extensions
”。请务必在真实网页上试用该扩展程序,例如http://www.yilijishu.info/。
给用户 options
该扩展程序目前仅允许用户将背景更改为绿色。包含选项页面可以让用户更好地控制扩展程序的功能,进一步自定义他们的浏览体验。
首先在名为 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.json
中注册选项页面,
{
"name": "Getting Started Example",
...
"options_page": "options.html"
}
重新加载扩展并右键单击工具栏中的扩展图标,然后选择选项。或者,单击详细信息并向下滚动详细信息页面并选择扩展选项。
最后一步是添加选项逻辑。使用以下代码在扩展的目录中创建一个名为 options.js
的文件。
let page = document.getElementById("buttonDiv");
let selectedClassName = "current";
const presetButtonColors = ["#3aa757", "#e8453c", "#f9bb2d", "#4688f1"];
// 通过标记所选按钮并保存对按钮单击做出反应
// 选择
function handleButtonClick(event) {
// 从先前选择的颜色中删除样式
let current = event.target.parentElement.querySelector(
`.${selectedClassName}`
);
if (current && current !== event.target) {
current.classList.remove(selectedClassName);
}
// 将按钮标记为选中
let color = event.target.dataset.color;
event.target.classList.add(selectedClassName);
chrome.storage.sync.set({ color });
}
// 为每种提供的颜色向页面添加一个按钮
function constructOptions(buttonColors) {
chrome.storage.sync.get("color", (data) => {
let currentColor = data.color;
// 对于我们提供的每种颜色......
for (let buttonColor of buttonColors) {
// ...创建一个具有该颜色的按钮...
let button = document.createElement("button");
button.dataset.color = buttonColor;
button.style.backgroundColor = buttonColor;
// …标记当前选择的颜色…
if (buttonColor === currentColor) {
button.classList.add(selectedClassName);
}
// ..并为单击该按钮时注册一个侦听器
button.addEventListener("click", handleButtonClick);
page.appendChild(button);
}
});
}
// Initialize the page by constructing the color options
constructOptions(presetButtonColors);
提供四种颜色选项,然后在带有 onclick 事件侦听器的选项页面上生成按钮。当用户单击按钮时,它会更新扩展程序存储中的颜色值。由于所有扩展的文件都从该存储中提取颜色信息,因此不需要更新其他值。
配置文件说明
{
// 清单文件的版本,这个必须写,而且必须是2或3(依浏览器版本而定)
"manifest_version": 2,
// 插件的名称
"name": "hello-world-plugin",
// 插件的版本
"version": "1.0.0",
// 插件描述
"description": "简单的Chrome扩展demo",
// 图标,一般偷懒全部用一个尺寸的也没问题
"icons": {
"16": "img/icon.png",
"48": "img/icon.png",
"128": "img/icon.png"
},
// 会一直常驻的后台JS或后台页面
"background": {
// 2种指定方式,如果指定JS,那么会自动生成一个背景页
"page": "background.html"
//"scripts": ["js/background.js"]
},
// 浏览器右上角图标设置,browser_action、page_action、app必须三选一
"browser_action": {
"default_icon": "img/icon.png",
// 图标悬停时的标题,可选
"default_title": "hello-world-plugin",
"default_popup": "popup.html"
},
// 当某些特定页面打开才显示的图标
/*"page_action":
{
"default_icon": "img/icon.png",
"default_title": "我是pageAction",
"default_popup": "popup.html"
},*/
// 需要直接注入页面的JS
"content_scripts": [
{
//"matches": ["http://*/*", "https://*/*"],
// "<all_urls>" 表示匹配所有地址
"matches": ["<all_urls>"],
// 多个JS按顺序注入
"js": ["js/jquery-1.8.3.js", "js/content-script.js"],
// JS的注入可以随便一点,但是CSS的注意就要千万小心了,因为一不小心就可能影响全局样式
"css": ["css/custom.css"],
// 代码注入的时间,可选值: "document_start", "document_end", or "document_idle",最后一个表示页面空闲时,默认document_idle
"run_at": "document_start"
},
// 这里仅仅是为了演示content-script可以配置多个规则
{
"matches": ["*://*/*.png", "*://*/*.jpg", "*://*/*.gif", "*://*/*.bmp"],
"js": ["js/show-image-content-size.js"]
}
],
// 权限申请
"permissions": [
"contextMenus", // 右键菜单
"tabs", // 标签
"notifications", // 通知
"webRequest", // web请求
"webRequestBlocking",
"storage", // 插件本地存储
"http://*/*", // 可以通过executeScript或者insertCSS访问的网站
"https://*/*" // 可以通过executeScript或者insertCSS访问的网站
],
// 普通页面能够直接访问的插件资源列表,如果不设置是无法直接访问的
"web_accessible_resources": ["js/inject.js"],
// 插件主页,这个很重要,不要浪费了这个免费广告位
"homepage_url": "https://www.baidu.com",
// 覆盖浏览器默认页面
"chrome_url_overrides": {
// 覆盖浏览器默认的新标签页
"newtab": "newtab.html"
},
// Chrome40以前的插件配置页写法
"options_page": "options.html",
// Chrome40以后的插件配置页写法,如果2个都写,新版Chrome只认后面这一个
"options_ui": {
"page": "options.html",
// 添加一些默认的样式,推荐使用
"chrome_style": true
},
// 向地址栏注册一个关键字以提供搜索建议,只能设置一个关键字
"omnibox": { "keyword": "go" },
// 默认语言
"default_locale": "zh_CN",
// devtools页面入口,注意只能指向一个HTML文件,不能是JS文件
"devtools_page": "devtools.html"
}