快捷键 commands
本教程共 56 篇 · 第 33 篇 · 更新于 2026-08-13 · 约 7 分钟阅读
本节目标:学完你能给扩展绑定键盘快捷键,会用保留命令
_execute_action一键打开弹出页,也会声明自定义命令并在后台接住 onCommand,还知道组合键有哪些硬性规则。
模块七的最后一节。前面八个界面组件都得动鼠标:点图标、点菜单、点面板。这一节讲怎么让用户完全脱离鼠标——按一下组合键,功能就跑起来。
对高频使用的扩展来说,快捷键的价值被严重低估。翻译、截图、收藏、开关某个功能,这些一天要用十几次的动作,配上快捷键体验完全不一样。
33-1 commands 的两种命令
commands 字段里能声明两类命令,区别很重要:
- 保留命令:名字以下划线开头,浏览器内置了行为,你只管声明,不用写任何 JS。Manifest V3 里最常用的就是
_execute_action。 - 自定义命令:名字由你定,比如
toggle-feature。浏览器只负责”按键了就通知你”,具体干什么要自己在后台写监听。
先记下这条对照:要打开 popup 用保留命令,要执行逻辑用自定义命令。
33-2 清单声明的完整结构
commands 是清单顶层字段,值是一个对象,每个 key 就是一个命令名:
{
"manifest_version": 3,
"name": "快捷键示例",
"version": "1.0.0",
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html"
},
"commands": {
"run-action": {
"suggested_key": {
"default": "Ctrl+Shift+Y",
"mac": "Command+Shift+Y"
},
"description": "Run the sample action"
},
"toggle-feature": {
"suggested_key": {
"default": "Ctrl+Shift+U",
"mac": "Command+Shift+U"
},
"description": "Toggle a feature on or off"
}
}
}
每个命令下面两个字段:
suggested_key:建议的组合键。default是通用键位,mac单独指定 macOS 上的键位(还支持windows、linux、chromeos)。description:命令的说明文字。它会显示在浏览器的快捷键设置页里,用户看到的就是这句话,所以写清楚点。
Note
suggested_key字面意思就是”建议”。如果这个组合键已经被浏览器自身或别的扩展占用,你的建议不会生效,命令会处于”未设置”状态,得用户手动去分配。这不是 bug,是设计如此。
description 对自定义命令是必填的。保留命令的 description 可以省略,因为浏览器有默认文案,但我建议还是写上中文说明,用户在设置页看得更明白。
33-3 保留命令 _execute_action
最省事的一个:绑定快捷键到工具栏按钮。按键效果 = 点了一次扩展图标。
{
"manifest_version": 3,
"name": "我的扩展",
"version": "1.0.0",
"action": {
"default_popup": "popup.html"
},
"commands": {
"_execute_action": {
"suggested_key": {
"default": "Ctrl+Shift+Y",
"mac": "Command+Shift+Y"
},
"description": "打开扩展弹出页"
}
}
}
就这样,一行 JS 都不用写。用户按 Ctrl+Shift+Y,popup 就弹出来了。
如果 action 没配 default_popup,那按快捷键就等于触发 chrome.action.onClicked,你在后台监听它即可:
chrome.action.onClicked.addListener((tab) => {
console.log('图标被点了,或者快捷键被按了', tab.id);
});
Tip
_execute_action是 Manifest V3 下唯一常用的保留命令。它对应的是清单里的action字段,也就是 MV3 唯一的工具栏按钮入口。
33-4 自定义命令 + onCommand 监听
自定义命令的完整链路是两段:清单里声明名字,后台用 chrome.commands.onCommand 接住。
let featureEnabled = false;
chrome.commands.onCommand.addListener(async (command) => {
if (command === 'run-action') {
chrome.notifications.create({
type: 'basic',
iconUrl: 'images/icon-128.png',
title: 'Commands API Demo',
message: 'The "run-action" command was triggered.'
});
}
if (command === 'toggle-feature') {
featureEnabled = !featureEnabled;
const state = featureEnabled ? 'ON' : 'OFF';
chrome.action.setBadgeText({ text: featureEnabled ? 'ON' : '' });
chrome.action.setBadgeBackgroundColor({ color: '#4688F1' });
chrome.notifications.create({
type: 'basic',
iconUrl: 'images/icon-128.png',
title: 'Feature Toggled',
message: `The feature is now ${state}.`
});
}
});
回调的第一个参数就是清单里那个命令名字符串。所以命名要有辨识度,别用 cmd1、cmd2 这种。
监听器还能拿到第二个参数——当前标签页:
chrome.commands.onCommand.addListener((command, tab) => {
if (command === 'copy-title') {
console.log('当前页面标题:', tab.title);
}
});
这里有一个必须记牢的坑:
Warning
onCommand监听器必须写在服务工作者(Service Worker)的顶层,不能包在函数里或异步逻辑之后。后台是随时休眠的,用户按快捷键时后台可能已经睡了,只有顶层注册的监听器才能把它唤醒。写错位置的表现是”有时候好使有时候不好使”,特别难查。
还有个坑关于状态。上面例子里的 featureEnabled 是个全局变量,后台一休眠它就丢了。真实项目里请用 chrome.storage 存:
chrome.commands.onCommand.addListener(async (command) => {
if (command !== 'toggle-feature') return;
const { enabled = false } = await chrome.storage.local.get('enabled');
const next = !enabled;
await chrome.storage.local.set({ enabled: next });
await chrome.action.setBadgeText({ text: next ? 'ON' : '' });
});
33-5 组合键有硬规则
suggested_key 不能随便填,浏览器有一套限制,不满足就直接加载失败或命令不生效。
必须带修饰键。 组合键里必须包含 Ctrl 或 Alt 之一。macOS 上可以用 Command 或 MacCtrl。单个字母 Y、单个 Shift+Y 都不行。
Shift 只能当副修饰键。 也就是 Ctrl+Shift+Y 合法,Shift+Y 不合法。
Ctrl+Alt 组合要慎用。 部分键盘布局里 Ctrl+Alt 等于 AltGr,容易和其他软件或输入法打架,建议避免。
主键的取值范围有限。 允许的有:A–Z、0–9、Comma、Period、Home、End、PageUp、PageDown、Space、Insert、Delete、四个方向键,以及媒体键 MediaNextTrack、MediaPlayPause、MediaPrevTrack、MediaStop。
媒体键有个特例:它们不需要修饰键,可以单独绑定。
{
"commands": {
"play-pause": {
"suggested_key": { "default": "MediaPlayPause" },
"description": "播放或暂停"
}
}
}
跨平台键位分开写。 macOS 上的 Ctrl 在物理上是 Control 键,而用户习惯的是 Command。所以给 Mac 单独指定:
{
"commands": {
"open-panel": {
"suggested_key": {
"default": "Ctrl+Shift+P",
"mac": "Command+Shift+P",
"windows": "Ctrl+Shift+P",
"linux": "Ctrl+Shift+P"
},
"description": "打开面板"
}
}
}
只写 default 时,macOS 上 Ctrl 会被自动映射成 Command,所以偷懒只写 default 通常也能用。但显式写 mac 更可控。
Note还有个数量限制:一个扩展可以声明很多命令,但浏览器只会自动分配前四个建议快捷键。超出的命令仍然存在、仍然能被
onCommand接到,只是默认没有键位,需要用户自己去设置页分配。所以把最重要的命令写在前面。
33-6 全局快捷键 global
默认情况下,快捷键只在浏览器窗口获得焦点时有效。如果你希望用户在别的软件里也能按,加 "global": true:
{
"commands": {
"quick-capture": {
"suggested_key": {
"default": "Ctrl+Shift+1",
"mac": "Command+Shift+1"
},
"description": "快速记录",
"global": true
}
}
}
全局快捷键的限制更严:只支持 Ctrl+Shift+[0–9] 这一类组合(Mac 上是 Command+Shift+[0–9])。写别的组合配 global: true,全局特性不会生效。
而且它是抢占系统级按键,容易和其他软件冲突。我建议只在真正需要”浏览器不在前台也能用”的场景才开,比如快速剪藏工具。
33-7 查询实际绑定:commands.getAll
因为建议键可能落空、用户也可能改键,你在界面上显示”快捷键是 XX”时,不能直接照抄清单里的值,得去查真实生效的绑定。
chrome.commands.getAll() 返回当前所有命令及其实际键位:
async function listCommands() {
const commands = await chrome.commands.getAll();
const container = document.getElementById('commands');
for (const command of commands) {
const row = document.createElement('div');
row.className = 'command-row';
const name = document.createElement('span');
name.className = 'command-name';
name.textContent = command.description || command.name;
const shortcut = document.createElement('kbd');
shortcut.textContent = command.shortcut || 'Not set';
row.appendChild(name);
row.appendChild(shortcut);
container.appendChild(row);
}
}
listCommands();
每个 command 对象上有三个字段:name(命令名)、description(说明)、shortcut(实际生效的组合键,未分配时是空字符串)。
这段代码放在 popup 里最合适——用户打开弹出页就能看到自己的快捷键清单。注意用 createElement + textContent 拼 DOM,别用 innerHTML 拼字符串,这是扩展里应有的安全习惯。
33-8 让用户改键
浏览器提供了统一的快捷键管理页:chrome://extensions/shortcuts。用户在这里能看到所有扩展的命令,并逐个改键、切换全局范围。
你可以在 popup 里放个入口引导用户过去:
document.getElementById('edit-shortcuts').addEventListener('click', () => {
chrome.tabs.create({ url: 'chrome://extensions/shortcuts' });
});
Tip用户手动设置的键位优先级高于
suggested_key。他改过之后,你在清单里改建议值也不会覆盖他的选择——这是好事,别试图绕过。
33-9 小结:模块七收尾
快捷键这一节的骨架很短:清单 commands 里声明命令 → 保留命令 _execute_action 零代码打开 popup → 自定义命令在服务工作者顶层用 onCommand 接住 → suggested_key 遵守修饰键和主键规则 → 用 getAll() 查真实绑定、引导用户去 chrome://extensions/shortcuts 改键。
到这里,模块七的八个界面组件全部讲完了:popup 弹出页、options 选项页、右键菜单、地址栏 omnibox、侧边栏、通知、devtools 面板、快捷键。你现在手上有一整套”和用户打交道”的工具,可以按交互形态挑合适的那个:
- 快速操作 → popup + 快捷键
- 长期伴随 → 侧边栏
- 设置项 → options 页
- 页面内右键 → contextMenus
- 跳出浏览器提醒 → notifications
- 前端调试工具 → devtools 面板
界面搭好了,接下来该往里面填能力。下一个模块进入常用 API,从最基础的 storage 存储开始——你的扩展怎么把数据存下来、跨设备同步、并在变化时收到通知。