系列文章可以查看《浏览器扩展程序开发笔记》专栏
Action
参考:
chrome.action
API- 关于 Action 的官方示例
该交互控件是指在浏览器工具栏的扩展程序图标,供用户点击,可以执行预定的操作。它也可以作为唤起其他交互控件的入口,例如通过适当的配置,在悬停时可以显示提示框 tooltip,在点击时可以弹出弹出框 popup。
💡 在 MV2 版本中有 API chrome.browserAction
(浏览器级别的按钮,对所有页面都可以响应)和 API chrome.pageAction
(针对特定匹配条件的页面才会响应);而在 MV3 版本中新增了 chorme.action
API,它的功能有点像是 MV2 的 Browser Action,如果希望实现类似于 Page Action 的功能,可以参考官方示例;
-
如果要使用该控件,需要先在配置清单
manifest.json
的选项action
中进行声明注册,例如指定图标文件的相对路径,如果使用了 popup 要指定弹出框的 HTML 文件。{ // ... "action": { // 图标文件 "default_icon": { // optional "16": "images/icon16.png", // optional "24": "images/icon24.png", // optional "32": "images/icon32.png" // optional }, // 提示框 "default_title": "Click Me", // optional, shown in tooltip // 弹出框 "default_popup": "popup.html" // optional }, }
💡 即使扩展程序的配置清单中没有设置
action
选项,它也可以显示在浏览器工具栏上,会使用一个默认图标,一般以背景色为灰底且包含扩展程序的首字母的图标指代。 -
图标
icon 图标的默认高和宽都是 16 DIPs(device-independent pixels),推荐预设多个尺寸的图标,浏览器会使用恰当的文件。图标文件的格式需要是 Blink 渲染引擎所支持的,例如 PNG、JPEG、BMP、ICO 等,而 SVG 是不支持的。如果是解压的扩展程序,则只支持 PNG 格式。
除了在配置清单
manifest.json
的选项action.default_icon
中提供固定的文件,还有通过编程的方式,使用方法chrome.action.setIcon()
设置图标,可以根据条件设置不同的图片路径,也可以使用 canvas 创建图片。⚠️ 该方法是用于设置静态图片,而不应该用于设置动图。const canvas = new OffscreenCanvas(16, 16); const context = canvas.getContext('2d'); context.clearRect(0, 0, 16, 16); context.fillStyle = '#00FF00'; // Green context.fillRect(0, 0, 16, 16); const imageData = context.getImageData(0, 0, 16, 16); chrome.action.setIcon({imageData: imageData}, () => { /* ... */ });
-
提示框
tooltip 是在用户悬停在图标时显示的提示框,可以设置一段简短的文字,用以提示该扩展程序的名称。
💡 当图标按钮被聚焦时,它可以被屏幕阅读软件识别,可以增强扩展程序的可及性。
除了在配置清单
manifest.json
的选项action.default_title
中设置文字,还可以使用方法chrome.action.setTitle()
进行设置。 -
弹出框
popup 是在用户点击图标时显示的弹出框,它实际上是一个大小受到限制(高和宽的最小值是 25px,高的最大值是 600px,宽的最大值是 800px)的 HTML 页面,默认大小是基于内容的。
除了在配置清单
manifest.json
的选项action.default_popup
中设置 popup 页面,还可以使用方法chrome.action.setPopup()
动态更新弹出框所指向的 HTML 文件的路径。 -
标记
badge 是一个添加到图标上的文字,并允许设置背景色,一般用以显示扩展程序的状态,例如更新了新版本可以显示
new
,如果扩展程序带统计功能则可以形式数值等。⚠️ 由于标记的空间有限,所以一般只能显示 4 个或以下的字符
通过方法
chrome.action.setBadgeText()
设置标记文字;通过chrome.action.setBadgeBackgroundColor()
设置标记的背景色chrome.action.setBadgeBackgroundColor( {color: [0, 255, 0, 0]}, // Green () => { /* ... */ }, ); chrome.action.setBadgeBackgroundColor( {color: '#00FF00', // Also green () => { /* ... */ }, ); chrome.action.setBadgeBackgroundColor( {color: 'green'}, // Also, also green () => { /* ... */ }, );
-
action 在每一个标签页都可以有不同的状态,例如可以针对不同的标签页,设置不同 badge 内容
function getTabId() { /* ... */} function getTabBadge() { /* ... */} chrome.action.setBadgeText( { text: getTabBadge(tabId), tabId: getTabId(), }, () => { ... } );
💡 如果方法
setBadgeText
第一个参数的选项tabId
省略了,则该标记会作为全局设置,而提供了tabId
则针对特定的标签页,优先级更高,会覆盖全局设置的标记文字。 -
默认所有标签页下,action 图标都是可以响应点击的 clickable,可以通过方法
chrome.action.enable()
或chrome.action.disable()
来手动控制 action 的响应状态,这会影响 popup 的显示或chrome.action.onClicked
所监听的相应事件的分发。
Context Menu
参考:
chrome.contextMenus
API- 关于 Context Menu 官方示例
该交互控件是指浏览器的右键菜单,可以通过扩展程序往其中添加选项,除了可以针对整个页面,还可以针对特定的 DOM 元素,或 action 图标,添加右键菜单项。
-
如果要使用该控件,需要先在配置清单
manifest.json
的选项permissions
中进行声明注册。为了便于将菜单选项与扩展程序相匹配,需要在配置清单的选项icons
中指定图标文件,最好提供多种尺寸的图片文件。{ // ... "permissions": [ "contextMenus" ], "icons": { "16": "icon-bitty.png", "48": "icon-small.png", "128": "icon-large.png" }, }
-
使用方法
chrome.contextMenus.create({}, callback())
为扩展程序创建专属的菜单项,它可以接收两个入参,第一个参数是配置对象,第二个参数是回调函数。返回值该菜单选项的唯一 ID 值。配置对象有多个选项,常用如下:
id
为当前菜单选项分配一个唯一 IDtitle
(必须,除非该菜单选项的类型是分割线type: "separator"
)菜单选项的内容type
菜单选项的类型,默认值是normal
,就是正常的菜单选项,还可以是checkbox
、radio
、separator
contexts
数组,限制菜单选项出现在对页面的哪个元素进行右键点击时,默认值是['page']
,即在整个网页任何地方右键点击时,该菜单选项都显示在菜单中parentId
当前菜单选项的父级菜单的 IDonclick
监听菜单选项的点击事件和事件处理函数,当菜单选项被点击时执行该事件处理函数,会有两个入参info
(该菜单选项的信息)和tab
(当前标签页的信息)传入
(可选)回到函数是在用户右键点击,该菜单选项被创建时所执行的
-
使用方法
chrome.contextMenus.update(menuItemId, {}, callback())
更新给定菜单选项,第一个参数是菜单选项的唯一 ID 值,第二个参数是配置对象(和方法chrome.contextMenus.create()
的配置对象可使用的选项一样),第三个(可选)参数是回调函数,在更新完菜单选项后执行。
💡 浏览器的右键菜单是全局的,可以出现在任何页面中,甚至是 file://
或 chrome://URLs
的页面,如果希望控制菜单选项出现在指定的页面,你可以在创建 create()
或更新 update()
菜单选项时,通过配置对象的选项 documentUrlPatterns
来限制只能在特定的 URL 页面或 <iframe>
中,右键点击才显示相应的菜单项。
- 使用方法
chrome.contextMenus.remove(menuItemId, callback())
动态删除已创建的菜单选项。(可选)回调函数在删除指定的菜单选项后执行。如果想删除所有该扩展程序创建的菜单选项,可以使用方法chrome.contextMenus.removeAll(callback())
其(可选)回调函数会在删除菜单选项后执行。 - 可以创建多个菜单选项,但是如果选项多于一个,浏览器会自动将它们收纳到一个次级菜单中
- 使用方法
chrome.contextMenus.onClicked(callback())
监听该扩展程序菜单选项的点击事件,并执行相应的事件处理函数,该函数接收两个入参info
被点击的菜单选项的相关信息,tab
标签页相关信息。
Omnibox
参考:
chrome.omnibox
API- 关于 Omnibox 的官方示例
该交互控件是指地址栏上的搜索关键词,当用户在地址栏输入相应的关键词,就会触发 Omnibox(唤起相应的扩展程序),接下来用户在地址栏中输入内容是直接与该扩展程序进行交互。一般会在扩展程序中预先设置一系列的搜索建议,当用户输入的内容模糊匹配成功时,就会在一个 dropdown 中显示相应的搜索建议。
-
如果要使用该控件,需要先在配置清单
manifest.json
的选项omnibox
中进行声明注册。当 Omnibox 被触发时,扩展程序图标(以灰阶的形式展示)和名称会显示在地址栏的左侧,为了便于识别,需要在配置清单的选项icons
中指定图标文件,最好提供多种尺寸的图片文件(默认使用高和宽为 16px 的图标)。该控件的交互逻辑在后台脚本的 service worker 中设置(需要在配置清单
manifest.json
的选项background.service_worker
中声明注册),基于事件监听-响应的原理。{ // ... "background": { "service_worker": "background.js" }, "omnibox": { "keyword" : "demo" }, "icons": { "16": "icon-bitty.png", "48": "icon-small.png", "128": "icon-large.png" }, }
以上示例将扩展程序的 Omnibox 触发关键词设定为
demo
,当用户在地址栏输入 demo 时,会在下拉框显示一个扩展程序名称的选项,可以点击该选项,或按 Tab 键,或键入空格 Space,即可触发 Omnibox。
-
常用于监听事件的 API 如下:
-
onInputChanged
进入 Omnibox 模式后,当用户在地址栏中输入内容时会触发。chrome.omnibox.onInputChanged.addListener((text, suggest) => { if(!text) return; suggest([ { content: text, description: `search for ${text}` } ]) });
事件处理函数中接收两个入参,第一个参数
text
是用户输入的内容(字符串),第二个参数suggest
是一个方法,它接收一个数组,包含一系列的建议结果 SuggestResult,该方法会将这些建议选项传递回浏览器,显示在地址栏的下拉框中。💡 建议结果 SuggestResult 是一个对象,以供用户选择,包括以下属性:
content
实际上会输入到地址栏的内容,当用户选中该建议选项时,会传递给扩展程序的内容deletable
该建议选项是否可以让用户删除description
描述内容,显示在地址栏的下拉框中,可以包含 XML 风格的样式修饰。但是不能包含 5 种 XML 转义字符。
💡 可以使用方法
chrome.omnibox.setDefaultSuggestion(suggestion)
设置默认的建议选项,该方法接收的入参是一个不完整 suggestionResult 对象,没有content
属性,其作用类似于输入框中的 placeholder。当触发了 Omnibox 时,在用户还没输入内容时,该默认建议就会出现在地址栏的下拉框中第一条的位置。⚠️ 根据一个 Bug 报告,由于 Omnibox 的搜索建议内容支持 XML,所以需要调用 DomParser,但是后台脚本在 MV3 版本迁移改用了 service worker,该运行环境并没有 DomParser,所以会导致报错,且无法正常显示搜索建议选项。
-
onInputEntered
在用户选择执行一个建议选项后,触发回调函数。chrome.omnibox.onInputEntered.addListener((text, disposition) => { if(!text) return; console.log('inputEntered: ' + text); // Encode user input for special characters , / ? : @ & = + $ # var newURL = 'https://www.google.com/search?q=' + encodeURIComponent(text); chrome.tabs.create({ url: newURL }); console.log(disposition) });
事件处理函数接收两个参数,第一个参数
text
是输入到地址栏的内容,第二个参数disposition
是进行搜寻时窗口的设置,有三种可能的结果:-
currentTab
在当前标签页进行搜寻 -
newForegroundTab
新建一个标签页进行搜寻,同时切换到该标签页 -
newBackgroundTab
新建一个标签页进行搜寻,但不进行标签页的切换
以上示例调用了
chrome.tabs.create()
方法,在当前标签页进行搜索,所以终端打印的值是currentTab
-
-
Override Pages
参考:
-
关于 Override Pages 的官方示例
- historyOverride(MV2 版本)
- blank_ntp(MV2 版本)
- override_igoogle(MV2 版本)
该交互控件是通过覆写页面实现的,扩展程序可以覆写三个 Chrome 的特殊页面:
- Bookmark Manager:书签管理页面
chrome://bookmarks
- History:历史记录页面
chrome://history
- New Tab:新建标签页
chrome://newtab
💡 每一个扩展程序只能覆写以上三个特殊 Chrome 页面之,而每一种特殊 Chrome 页面,只能选择被一个扩展程序进行覆写。此外隐身模式下,新建标签页不能被覆写。
-
如果要使用该控件,需要先在配置清单
manifest.json
的选项chrome_url_overrides
中进行声明注册,将需要覆写的页面作为属性,bookmarks
、history
、newtab
三者之一,属性值就是用以替换的 HTML 页面文档的相对路径。{ // ... "chrome_url_overrides" : { "newTab": "newPage.html" }, ... }
-
为了提供更好的用户体验,用以替换的页面应该遵循以下指引:
- 页面文件大小应该较小,便于快速加载显示,避免使用同步访问网络或数据库资源,导致渲染阻塞。
- 包含明确的信息,告知用户当前浏览的是 Chrome 的特殊页面。
- 不要在新建标签页使用输入框聚焦功能,因为新建页面时,标签页的地址栏会首先获取焦点。
Commands
参考:
- 关于 Commands 的官方示例
该交互控件是指使用快捷键操作扩展程序,可以通过快捷键激活 action 或执行特定的命令。
💡 所有扩展程序的快捷键都在 chrome://extensions/shortcuts
中显示,用户可以在其中修改快捷键的组合值,或快捷键的局部与全局适用性。
-
如果要使用该控件,需要先将这些快捷键在配置清单
manifest.json
的选项commands
中进行声明注册,该选项的值是一个对象,属性名是一个描述命令的名称,属性值是关于快捷键定义的对象,一般有两个选项:suggested_key
(可选)声明默认的快捷键,其值可以是一个表示(跨平台适用的)快捷键的字符串,或是一个对象,可以针对不同的系统平台设定不同的快捷键,其中系统平台支持default
、chromeos
、linus
、mac
、windows
。如果该选项省略,则该命令没有相应的触发快捷键,等待用户来设定后再生效。description
一段告知用户该快捷键功能作用的字符串,它会显示在扩展程序的快捷键管理界面中chrome://extensions/shortcuts
,对于标准快捷键 standard commands 它是必须的,对于 action commands 是可选的。
{ // ... "commands": { "run-foo": { "suggested_key": { "default": "Ctrl+Shift+Y", "mac": "Command+Shift+Y" }, "description": "Run \"foo\" on the current page." }, "_execute_action": { "suggested_key": { "windows": "Ctrl+Shift+Y", "mac": "Command+Shift+Y", "chromeos": "Ctrl+Shift+U", "linux": "Ctrl+Shift+J" } } }, }
💡 其中
_execute_action
是保留属性,用以定义激活 action 的快捷键(对于 MV2 版本,则有_execute_browser_action
和_execute_page_action
保留属性,分别设定激活 browser action 和 page action 的快捷键),对于激活 action 的快捷键无法**触发command.onCommand
事件。💡 当新安装的扩展程序的快捷键默认值,与已安装的其他扩展程序的快捷键冲突时,对于后来安装的扩展程序,浏览器就不会再注册这些快捷键,避免覆盖之前已存在的快捷键。为了避免让用户觉得快捷键「无故失灵」的现象,我们应该采用以下更健壮的方法,在安装扩展程序时
chrome.runtime.onInstalled.addListener
先进行检查快捷键冲突,并告知用户// background.js // Only use this function during the initial install phase. After // installation the user may have intentionally unassigned commands. chrome.runtime.onInstalled.addListener((reason) => { if (reason === chrome.runtime.OnInstalledReason.INSTALL) { checkCommandShortcuts(); } }); function checkCommandShortcuts() { // 获取当前插件已注册的快捷键 chrome.commands.getAll((commands) => { let missingShortcuts = []; for (let {name, shortcut} of commands) { // 如果冲突无法注册快捷键默认值,则 shortcut 值为空字符串 if (shortcut === '') { missingShortcuts.push(name); } } // 如果该扩展程序与其他扩展程序真的存在快捷键冲突 if (missingShortcuts.length > 0) { // Update the extension UI to inform the user that one or more // commands are currently unassigned. } }); }
-
快捷键必须包含
Ctrl
或Alt
两者之一,对大小写敏感,支持使用以下按键组合为快捷键:- 字母键
A-Z
- 数字键
0~9
- 标准的功能键
- 通用键
Comma
,Period
,Home
,End
,PageUp
,PageDown
,Space
,Insert
,Delete
- 方向键
Up
,Down
,Left
,Right
- 通用键
- 修饰键
Ctrl
,Alt
,Shift
,MacCtrl
(macOS only),Command
(macOS only),Search
(Chrome OS only)
💡 不支持
Tab
键,媒体键不能与修饰键组合。 - 字母键
-
为了响应快捷键,需要在后台脚本中使用
chrome.commands.onCommand.addListener
API 进行监听chrome.commands.onCommand.addListener((command) => { console.log(`Command: ${command}`); });
💡 和标准的快捷键 standard commands 不同,对于激活 action 的快捷键,无法通过以上方法进行监听。可以在弹出框 popup 的脚本文件中,监听
DOMContentLoaded
事件来替代。 -
默认情况下,注册的快捷键是 Chrome 浏览器的局部快捷键(当浏览器是当前系统的激活应用时,按下快捷键,扩展程序才响应),也可以在快捷键定义对象中,通过选项
global: true
设定为全局快捷键。建议注册全局快捷键限制在Ctrl+Shift+[0..9]
范围中,以避免覆盖掉其他系统级别的快捷键。{ // ... "commands": { "toggle-feature-foo": { "suggested_key": { "default": "Ctrl+Shift+5" }, "description": "Toggle feature foo", "global": true } }, }
💡 但是 Chrome OS 不支持扩展程序设定全局快捷键