addeventlistener第三个参数true表示捕获阶段、false或省略表示冒泡阶段;event.eventphase返回1/2/3分别对应捕获/目标/冒泡阶段;event.target始终为触发元素,this为监听绑定元素。

看 addEventListener 的第三个参数值
浏览器不提供运行时 API 直接告诉你「当前正在执行的是捕获还是冒泡阶段」,但你能从监听器注册时的配置反推它属于哪个阶段。关键就落在 addEventListener 的第三个参数:true 表示捕获阶段,false 或省略表示冒泡阶段。
这个参数不是“开关”,而是“声明”——你写 true,就是在告诉浏览器:“请把这个 handler 放到捕获路径上执行”。它不会动态改变,也不会在事件触发时再判断。
-
el.addEventListener('click', fn, true)→ 一定在捕获阶段执行 -
el.addEventListener('click', fn, false)→ 一定在冒泡阶段执行 -
el.addEventListener('click', fn)→ 等价于false,即冒泡阶段 -
el.addEventListener('click', fn, { capture: true })→ 和true效果一致
用 event.eventPhase 查当前所处阶段
真正能在 handler 内部判断“此刻事件流走到哪了”的,是 event.eventPhase 属性。它返回一个数字:
-
1:捕获阶段(Event.CAPTURING_PHASE) -
2:目标阶段(Event.AT_TARGET) -
3:冒泡阶段(Event.BUBBLING_PHASE)
注意:eventPhase 是只读的,且只在 handler 执行期间有效。例如:
parent.addEventListener('click', (e) => {
console.log(e.eventPhase); // 点击子元素时,父元素若在捕获阶段监听,这里输出 1
});
child.addEventListener('click', (e) => {
console.log(e.eventPhase); // 总是 2,无论第三个参数是 true 还是 false
});
别被 event.target 和 this 搞混
新手常误以为“this === event.target 就说明是目标阶段”,但这只能确认是否命中目标元素,不能说明传播阶段。比如:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 父元素用
{ capture: true }监听,点击子元素时:this是父元素,event.target是子元素,event.eventPhase === 1 - 父元素用默认(冒泡)监听,点击子元素时:
this是父元素,event.target是子元素,event.eventPhase === 3 - 子元素自身监听(无论
capture值):this === event.target,且event.eventPhase === 2
也就是说,event.target 永远指向原始触发者,而 this 指向当前绑定监听器的元素 —— 两者相等 ≠ 当前是目标阶段,只是碰巧监听器绑在了目标上。
哪些事件根本不会冒泡,查文档比猜更可靠
不是所有事件都走完整三阶段。比如 focus、blur、mouseenter、mouseleave 默认不冒泡,即使你给父元素绑了冒泡监听也收不到。这时候 event.eventPhase 在父元素 handler 中根本不会是 3,甚至可能压根不触发。
遇到监听没反应,先确认事件类型是否支持冒泡:
- 查 MDN 页面,看该事件的 “Bubbles” 栏是否标为 “Yes”
- 用
event.bubbles属性在 handler 中检查(返回布尔值) - 别依赖“应该能冒泡”的经验,
scroll和transitionend也都不冒泡
最易忽略的一点:捕获和冒泡不是互斥开关,而是两个独立可选的监听入口;你可以同时在父元素上既注册捕获监听,又注册冒泡监听,它们会按顺序分别执行 —— 这也是为什么调试时看到一堆日志却理不清顺序的根本原因。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










