事件流分捕获→目标→冒泡三阶段:捕获从window至目标父级,仅触发usecapture:true监听器;目标阶段在元素自身执行所有绑定监听器;冒泡从目标回传至window,仅触发usecapture:false监听器。

JavaScript 中事件机制的捕获与冒泡,本质是同一个事件在 DOM 树中按固定路径传播的两个方向阶段,加上中间的目标阶段,构成完整的“事件流”。理解它不靠死记,而要抓住路径、时机和控制点。
事件流严格分三步:捕获 → 目标 → 冒泡
以点击一个嵌套在三层 div 中的按钮为例(<div id="A"><div id="B"><button id="C">点我</button></div></div>):
-
捕获阶段:事件从
window出发 →document→→→#A→#B,**到 #C 的父级为止,不进入 #C 自身**;此阶段只触发设置了useCapture: true的监听器。 -
目标阶段:事件抵达
#C元素本身;此时无论监听器是true还是false,只要绑定在#C上,都会在此刻执行(true的监听器会比false的先执行)。 -
冒泡阶段:事件从
#C开始向上回传 →#B→#A→→document→window;此阶段只触发useCapture: false(或省略)的监听器。
监听器在哪一阶段生效,由第三个参数决定
addEventListener(type, handler, options) 的第三个参数直接控制监听时机:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
-
el.addEventListener('click', fn, true)→ 只在捕获阶段响应(从外向内路过时触发) -
el.addEventListener('click', fn)或el.addEventListener('click', fn, false)→ 只在冒泡阶段响应(从内向外路过时触发) -
el.addEventListener('click', fn, {capture: true})→ 等效于true,但支持额外选项如once、passive
注意:目标元素上的监听器,即使写 true,也总是在目标阶段执行,不是捕获阶段——这是规范明确规定的,不是 bug。
阻止传播要对症下药,不能混用
不同方法影响范围不同,选错会导致逻辑异常:
-
event.stopPropagation():只切断当前阶段后续路径。比如在#C的冒泡监听器里调用,#C 的事件仍会走完目标阶段,但不会再传到 #B 和 #A;它不影响捕获阶段已发生的或同一元素其他监听器的执行。 -
event.stopImmediatePropagation():立刻终止整个事件流,包括同一元素上尚未执行的其他监听器(哪怕它们是捕获或冒泡中不同顺序的),也阻止后续所有阶段。 -
event.preventDefault():和传播无关,只取消默认行为(如表单提交、链接跳转),事件照常传播。
实际场景中,捕获和冒泡各司其职
不是“哪个更好”,而是“谁更适合做什么”:
-
捕获阶段常用在顶层统一拦截:比如在
document上用addEventListener('click', handler, true)实现点击空白处关闭弹窗、权限点击拦截、全局快捷键预处理等,确保在事件到达具体业务元素前就介入。 -
冒泡阶段支撑事件委托:把监听器放在父容器(如
ul),监听子项(如li)点击,靠e.target判断真实来源;这依赖事件能顺利冒泡上来,所以子元素内部一般不随意调用stopPropagation()。 -
避免滥用阻止传播:组件化开发中,父组件可能依赖子组件事件冒泡做状态同步或日志上报,无差别加
stopPropagation()会破坏这种协作契约。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










