为什么监听键盘快捷键时 preventDefault 不生效?

宇文梓辰 阅读 32

我在做一个富文本编辑器,想用 Ctrl+B 实现加粗功能。但按下 Ctrl+B 时浏览器还是会触发默认的“书签”行为(比如 Chrome 会打开书签栏),我明明已经调用了 preventDefault(),不知道是哪里写错了。

我试过在 keydown 事件里判断 e.ctrlKey 和 e.key === ‘b’,也调用了 e.preventDefault(),但没用。是不是事件监听的位置不对?或者需要阻止其他事件?

<div contenteditable="true" id="editor">输入内容...</div>
<script>
  document.getElementById('editor').addEventListener('keydown', (e) => {
    if (e.ctrlKey && e.key === 'b') {
      e.preventDefault();
      document.execCommand('bold', false, null);
    }
  });
</script>
我来解答 赞 3 收藏
二维码
手机扫码查看
2 条解答
诸葛志煜
啊这个坑我踩过,浏览器对某些快捷键有特殊保护。省事的话直接在document上监听,别在div上监听:

document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.key === 'b' && document.activeElement.id === 'editor') {
e.preventDefault();
document.execCommand('bold', false, null);
}
});


记得加activeElement判断,不然会影响其他输入框。
点赞 1
2026-03-06 15:22
设计师亚楠
别走弯路,你这个写法其实没问题,问题出在事件监听的对象上。

你把事件加在了 contenteditable 的 div 上,但浏览器的快捷键行为(比如 Ctrl+B 打开书签栏)是在 document 或 window 层级触发的,不是在你那个 div 上。也就是说,当用户按下 Ctrl+B 时,浏览器先捕获了全局快捷键,再把 keydown 事件派发到当前焦点元素(也就是你的 div),但有些快捷键的默认行为根本不会等你到那个阶段——它们在更高层级就被拦截了。

正确做法是把监听器加到 document 上,或者更稳妥点,加到 window 上,而且要确保用捕获阶段(第三个参数设为 true),这样能比浏览器默认行为更早拦截。

我之前踩过这个坑,试过各种组合,最后发现只有在捕获阶段加到 window 上才稳:

window.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.key === 'b') {
e.preventDefault();
document.execCommand('bold', false, null);
// 顺便提醒:execCommand 已废弃,建议用 new ClipboardItem + selection API 或者 ProseMirror 这类库
}
}, true); // 注意第三个参数是 true,启用捕获阶段


另外,有些快捷键(比如 Ctrl+B、Ctrl+P、Ctrl+S)是浏览器保留的,即使 preventDefault 了,某些版本 Chrome 还是会弹出对话框,尤其是当焦点不在可编辑区域时。所以务必保证 editor 是 focus 状态,或者直接用 window 捕获阶段拦截。

最后提醒一句,现在 execCommand 基本算遗产 API 了,新项目尽量用 Selection + Range 自己控制,或者直接上 Slate、Lexical 这类成熟库,省得再掉进这种兼容性坑里。
点赞 5
2026-02-24 12:22