事件冒泡和事件捕获是DOM事件流的两个固有阶段:先捕获(document→目标),后冒泡(目标→document);addEventListener第三个参数决定监听阶段,true或{capture:true}为捕获,false或省略为冒泡;stopPropagation()仅中断当前阶段传播。

事件冒泡和事件捕获的本质区别
它们是 DOM 事件流的两个相反阶段,不是两种“可选模式”,而是浏览器固有行为的两个方向。事件触发时,**先捕获(从 document 向下到目标元素),再冒泡(从目标元素向上到 document)**。默认情况下,addEventListener 绑定的是冒泡阶段的监听器。
addEventListener 的第三个参数决定监听时机
这个布尔值或选项对象直接控制监听器在哪个阶段生效:
-
true→ 捕获阶段触发(例如:el.addEventListener('click', handler, true)) -
false(或省略)→ 冒泡阶段触发(最常见用法) -
{capture: true}→ 捕获阶段(现代写法,更清晰) -
{once: true, capture: false}→ 只在冒泡阶段执行一次
注意:onclick 等内联事件属性和 addEventListener 的冒泡版都只响应冒泡阶段,无法监听捕获阶段。
阻止传播用 stopPropagation(),但要注意阶段差异
调用 event.stopPropagation() 会立即中断当前阶段的传播路径,不影响另一阶段已注册但尚未触发的监听器:
立即学习“Java免费学习笔记(深入)”;
- 在捕获阶段调用 → 后续捕获监听器不执行,但目标阶段和冒泡阶段仍照常进行
- 在冒泡阶段调用 → 上层冒泡监听器不执行,但捕获和目标阶段已完成,不受影响
- 若想彻底阻止所有阶段,需在捕获阶段就调用
stopPropagation()
别混淆 stopImmediatePropagation():它还会阻止同一阶段内其他已注册的监听器(哪怕同是捕获或同是冒泡)。
实际开发中哪些场景必须关注捕获阶段?
绝大多数点击、输入类交互靠冒泡就够用了,捕获阶段主要用于底层控制或全局干预:
- 全局快捷键拦截(如
Esc关闭模态框),在document捕获阶段监听,避免被子元素stopPropagation()阻断 - 防止第三方组件意外阻止关键事件(比如某个 UI 库在按钮上阻止了
click冒泡,你在body捕获阶段仍能捕获) - 实现自定义事件委托的前置逻辑(如权限校验、日志埋点),在捕获阶段统一处理再放行
捕获阶段的监听器执行顺序是从外到内,而冒泡是从内到外;这点在嵌套结构中调试事件流向时容易被忽略。











