界面件:右键菜单、地址栏 omnibox、快捷键 commands
扩展和用户的「接触面」除了工具栏图标,还有三处常被忽略的位置:网页右键菜单、地址栏、全局快捷键。三者都是「用户主动触发」的入口,天然配合 activeTab 使用,权限成本极低。这一篇逐个给出最小可用实现。
contextMenus:右键菜单
需要 contextMenus 权限,manifest 加 permissions: ["contextMenus"]。菜单项应在 runtime.onInstalled 里注册(避免每次唤醒 worker 重复注册导致报错):
// background.js
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
id: "translate-selection",
title: "翻译 \"%s\"",
contexts: ["selection"]
});
});
chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === "translate-selection") {
chrome.storage.local.set({ pendingText: info.selectionText });
chrome.action.openPopup?.(); // 或发消息给 content script 展示结果
}
});
%s 是占位符:contexts 为 selection 时,会自动替换成用户选中的文字,菜单上直接显示「翻译 "hello"」。contexts 可选值很丰富:page、selection、link、image、video、audio、editable、frame、action、tab,其中 action 表示扩展图标右键弹出的菜单。多个菜单项用 parentId 组成层级,type 可为 normal、checkbox、radio、separator。documentUrlPatterns / targetUrlPatterns 两个过滤字段能精确控制菜单项在哪些页面、哪些链接目标上出现。
omnibox:把地址栏变成你的输入框
manifest 声明关键字(需要 omnibox 权限对应的 manifest 键):
{
"omnibox": { "keyword": "ts" },
"permissions": ["omnibox"]
}
用户在地址栏输入 ts 后按空格或 Tab,即进入扩展的输入模式,此后按键实时回调:
// background.js
chrome.omnibox.setDefaultSuggestion({
description: "搜索本地笔记:%s"
});
chrome.omnibox.onInputChanged.addListener((text, suggest) => {
suggest([
{ content: text, description: "精确查找 <match>" + text + "</match>" }
]);
});
chrome.omnibox.onInputEntered.addListener((text) => {
chrome.tabs.create({ url: `https://my-notes.app/search?q=${encodeURIComponent(text)}` });
});
事件链是 onInputStarted → onInputChanged(可给建议列表)→ onInputEntered(回车确认)→ onInputCancelled。这是「命令面板」类扩展的标配入口。
commands:全局快捷键
manifest 里声明,service worker 里监听:
"commands": {
"toggle-highlight": {
"suggested_key": { "default": "Ctrl+Shift+H", "mac": "Command+Shift+H" },
"description": "开关页面高亮"
},
"_execute_action": {
"suggested_key": { "default": "Ctrl+Shift+Y" }
}
}
// background.js
chrome.commands.onCommand.addListener((command) => {
if (command === "toggle-highlight") {
// 配合 activeTab + scripting 注入切换逻辑
}
});
规则要点:每个扩展至多声明 4 个默认快捷键(用户可在 chrome://extensions/shortcuts 自行增加更多);组合键必须含 Ctrl 或 Alt(macOS 上 Ctrl 自动转 Command,要真正的 Control 键用 MacCtrl);Ctrl+Alt 组合被禁止(与 AltGr 冲突);_execute_action 是保留命令名,作用是模拟点击工具栏图标。用户自定义的快捷键会覆盖建议值,代码里不要假设某个键一定绑定成功。
三件套的通用心法
它们都是「用户手势」,都能触发 activeTab 授权,所以注册了这三类入口的扩展,大多数情况下根本不需要 host_permissions——这是把权限清单做小的关键技巧。入口注册类代码统一放 onInstalled,事件监听统一放 worker 顶层。第五章实战项目「划词翻译」会把这些件串成一个完整产品,触发词、快捷键、菜单三入口齐上。
官方文档:https://developer.chrome.com/docs/extensions/reference/api/contextMenus 、 https://developer.chrome.com/docs/extensions/reference/api/commands
三件套的注册时机与生命周期
界面件最大的共性是「注册一次、长期生效」,因此注册时机统一放 runtime.onInstalled(安装与更新时执行),不要放 worker 顶层——worker 每次唤醒都会重跑顶层代码,contextMenus.create 会因 id 重复抛错。标准写法:
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.removeAll(() => {
chrome.contextMenus.create({ id: "root", title: "我的工具", contexts: ["page"] });
chrome.contextMenus.create({ id: "act-1", parentId: "root", title: "高亮选中", contexts: ["selection"] });
});
});
先 removeAll 再 create 的组合让更新版本的菜单定义总是干净落地。omnibox 与 commands 没有运行时注册概念(全在 manifest),但它们的事件监听必须在 worker 顶层同步挂上,否则唤醒时事件丢失。
快捷键冲突与用户教育
commands 的默认键位容易与用户已有习惯冲突(尤其 Ctrl+Shift 系列被大量扩展抢占)。设计时三个原则:避开 Chrome 自身快捷键(如 Ctrl+T、Ctrl+W 系统级优先不可覆盖);默认键位尽量冷门、组合规则里 Shift 可选;在扩展的说明页明确告知「若快捷键无效,到 chrome://extensions/shortcuts 检查绑定」。用户改绑后的键位会覆盖 suggested_key,代码逻辑不要假设具体键位,只响应 command 名称。
onCommand 的回调里通常配合 activeTab 立即注入,形成「按键即功能」的体验:
chrome.commands.onCommand.addListener(async (command) => {
if (command !== "toggle-highlight") return;
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
if (!tab?.url) return;
await chrome.scripting.executeScript({ target: { tabId: tab.id }, files: ["toggle-highlight.js"] });
});
omnibox 的建议列表细节
omnibox 体验的好坏在 onInputChanged 的建议质量。三个提升点:建议数量控制在 5 条内(列表过长反而难选);description 里用 <match> 标签高亮命中文字(XML 转义要自己做,<dim> 做次级灰字);defaultSuggestion 设为「最可能的动作」回车直达,减少一次选择。suggestion 的 content 是回车时传给 onInputEntered 的值,把结构化信息编码进去(如 search:xxx / open:xxx),entered 里再按前缀分发,这是标准的 omnibox 路由模式。
三件套的实战组合见第五章 《实战项目拆解》 篇的划词翻译项目。官方文档:https://developer.chrome.com/docs/extensions/reference/api/contextMenus 、 https://developer.chrome.com/docs/extensions/reference/api/commands
三件套对照速查
| 界面件 | 声明位置 | 核心事件 | 典型场景 |
|---|---|---|---|
| contextMenus | permissions | contextMenus.onClicked | 选中文字触发功能 |
| omnibox | omnibox + permissions | onInputChanged / onInputEntered | 命令面板、快速搜索 |
| commands | commands 键 | commands.onCommand | 快捷键唤起功能 |
三者都是用户手势入口,都可作为 activeTab 的触发方式。设计入口组合时的经验:高频功能上快捷键,低频功能进右键菜单,需要输入的走 omnibox。入口选择的原则见 正则实战 之外,更值得参考的是你自己的使用直觉——自己用着别扭的入口组合,用户只会更别扭。编辑器工程配置见 HBuilderX 效率技巧。
本章由 WorkBuddy 原创整理,API 行为依据 Chrome 扩展官方文档(Manifest V3)。
