做个快捷键功能才发现:key 和 code 完全是两码事
给编辑器加个快捷键:按 Ctrl/Cmd + S 保存,Esc 退出,Enter 提交。
写着写着发现三件事都对不上:在 Mac 上 Ctrl 不生效、用中文输入法打字时按回车居然触发了提交、换了键盘布局 KeyA 的位置也不对。
根子都在 KeyboardEvent 那几个属性上。
一、key / code / keyCode 是三个东西
一个"按键"事件里有三个看起来很像的字段,含义完全不同:
| 属性 | 含义 | 例:按下字母 A | 例:按下回车 |
|---|---|---|---|
key |
实际产生的"字符" | "a" / "A"(随 Shift 变) |
"Enter" |
code |
物理按键位置 | "KeyA"(不随布局变) |
"Enter" |
keyCode |
老式数字编码(已废弃) | 65 |
13 |
差别在哪:
key是"输出了什么字符"。按A配Shift就是"A",不配就是"a"。它会随输入法和大小写变。code是"按了哪个物理键"。不管你键盘什么布局,KeyA永远是左边那排第三个字母键。它不关心大小写、不关心字符。keyCode是上古时代的数字,各浏览器曾经不一致,规范已经标废弃,新代码别再用。
所以判断"用户按了保存"该用哪个?看场景:
// 判断"回车"——用 key 最直观
if (e.key === 'Enter') { ... }
// 判断"按了 A 键这个位置"——用 code(游戏、乐器映射常用)
if (e.code === 'KeyA') { ... }
二、组合键怎么判断
Ctrl / Cmd / Shift / Alt 不在 key 里单独给,而是放在四个布尔属性上:
document.addEventListener('keydown', (e) => {
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
e.preventDefault() // 拦掉浏览器默认的"保存网页"
save()
}
})
要点:
metaKey是 Mac 的 ⌘(Command),ctrlKey是 Windows/Linux 的 Ctrl。跨平台快捷键要两个都判断,否则 Mac 用户按 ⌘S 没反应。e.key === 's'用小写s。组合键里的字母键,无论有没有按 Shift,key都是小写字母("s"),别写成"S"。preventDefault()别忘了。像Ctrl+S、Ctrl+P、Ctrl+W这些,浏览器有默认行为(保存网页、打印、关标签页),不拦就会触发默认动作。e.key对组合键的主键也可能是"S"之外的。比如Ctrl + 数字的key是"1"不是Digit1,用key判断更稳。
三、输入法假触发的坑
这是做编辑器最容易翻车的地方。
用户在中文输入法里打字,打到一半按了回车选词——这个回车也会冒出 keydown,e.key === 'Enter' 为真。如果你在这时候提交表单,用户字还没打完就被发了出去。
解决:用 e.isComposing 判断。输入法组合输入过程中,这个属性是 true,组合结束才变 false:
input.addEventListener('keydown', (e) => {
if (e.isComposing) return // 正在用输入法组字,忽略
if (e.key === 'Enter') submit()
})
更古老的做法是监听 compositionend,但 isComposing 一个判断就够,优先用它。
四、几个容易忽略的点
-
keydown会重复触发。按住一个键不松,系统会持续发keydown(像打字时字母一直冒)。做"按一次执行一次"的功能(比如游戏跳跃),要么用keyup,要么自己加个"按下了没松开"的标志位去重:const pressed = new Set() document.addEventListener('keydown', (e) => { if (pressed.has(e.code)) return // 已经在按住,忽略重复 pressed.add(e.code) ... }) document.addEventListener('keyup', (e) => pressed.delete(e.code)) -
有些键
preventDefault没用。Ctrl+W、Ctrl+T这类标签页级操作,浏览器不让网页拦,拦了也白拦。涉及这些的快捷键得避开。 -
Esc不一定弹出来。全屏模式、弹窗里Esc可能已被系统占用了行为,别把"退出"只绑在 Esc 上。 -
只给可聚焦元素监听。在一个没焦点的
div上加keydown可能收不到事件,通常挂在document或具体输入框上。 -
code在笔记本小键盘上不一样。外接数字小键盘的1是Numpad1,不是Digit1,要做数字快捷键得两个都判断,或者干脆用key。
小结
快捷键翻车基本都栽在 KeyboardEvent 那三个属性上:key 是输出了什么字符(随 Shift/输入法变)、code 是按了哪个物理键(不随布局变)、keyCode 已废弃别用。跨平台组合键用 (ctrlKey || metaKey) 一起判断、记得 preventDefault;字母键用小写比对。最大的坑是输入法选词时的回车会假触发提交,用 e.isComposing 拦掉就稳了。把这几条记牢,一个不出怪事的快捷键功能就成了。
- 点赞
- 收藏
- 关注作者
评论(0)