应使用 keydown 监听快捷键:它即时触发、支持组合键和功能键;keypress 已废弃,keyup 易漏判;需全局监听 document、调用 preventDefault()、用 event.code 判定按键、过滤编辑态元素并防止监听器重复注册。

监听 keyboard 事件要用 keydown,不是 keypress 或 keyup
现代快捷键逻辑几乎都基于 keydown:它在按键按下瞬间触发,能捕获组合键(如 Ctrl+S)、功能键(F5)、甚至无字符键(ArrowUp)。keypress 已被废弃,且不触发 Ctrl 等修饰键;keyup 延迟明显,容易漏判连按或误触发。
实操建议:
- 全局监听用
document.addEventListener('keydown', handler),避免绑定到特定输入框导致失焦失效 - 务必在 handler 中调用
event.preventDefault()—— 否则浏览器可能执行默认行为(如F5刷新、Ctrl+T开新标签) - 用
event.ctrlKey/event.shiftKey/event.altKey/event.metaKey判断修饰键,别依赖event.key字符匹配(比如Ctrl+I和Ctrl+Shift+I的key都是"i")
event.code 和 event.key 到底该用哪个?
event.code 表示物理按键位置(如 "KeyS"、"F5"、"ArrowDown"),与键盘布局无关;event.key 表示当前按键输出的字符或语义(如 "s"、"S"、"F5"、"Enter"),受 CapsLock、Shift 影响。
快捷键判定优先用 event.code:
立即学习“前端免费学习笔记(深入)”;
- 用户切换输入法或使用非英文键盘时,
event.key可能变成中文字符或空字符串,但event.code始终稳定 - 区分大小写快捷键(如
Ctrl+S保存 vsCtrl+Shift+S另存为)应靠修饰键 +code,而非靠key === "s"或"S" - 例外:需要响应字母键且区分大小写语义时(极少见),才考虑
key,但必须同步检查shiftKey
避免快捷键冲突和误触发的三个关键点
用户装了插件、系统有全局热键、页面里还有 contenteditable 或 input,都可能导致快捷键失效或打架。
实操建议:
- 在
keydownhandler 开头加判断:if (event.target.matches('input, textarea, [contenteditable="true"]')) return,防止在编辑态触发快捷键(除非你明确要支持编辑中快捷操作) - 用
event.stopImmediatePropagation()阻止其他同级监听器执行,尤其当多个模块都监听document时 - 注册前先移除旧监听:
document.removeEventListener('keydown', oldHandler),否则热更新或组件重复挂载会叠加监听器,造成多次执行
React/Vue 中实现快捷键要绕开合成事件陷阱
React 的 onKeyDown 是合成事件,不支持直接监听 document 级组合键;Vue 的 @keydown 默认绑定在组件根元素上,失焦即失效。
正确做法是手动绑定原生事件:
- React:在
useEffect里用document.addEventListener('keydown', handler),并返回清理函数 - Vue:在
mounted中绑定,beforeUnmount中解绑;或者用自定义指令封装keydown监听逻辑 - 两者都要注意:不要在 handler 里直接读取闭包中的 state 变量(易 stale),改用
ref或useState的回调式更新
Ctrl+S 被 textarea 拦截了,用户根本不会意识到问题出在事件没过滤,只会觉得“这功能坏了”。



















