事件冒泡和捕获是浏览器默认执行的两个阶段:捕获从window到目标元素下行,需显式启用监听;冒泡从目标元素向上传播,为默认行为,支持事件委托。

事件冒泡和捕获不是“要不要用”的选择,而是浏览器默认就发生的两个阶段——你没写任何代码,它们也在运行。
事件捕获阶段:从 window 到目标元素的“下行路径”
当点击一个嵌套很深的 只有显式开启才能监听它: 点击 立即学习“Java免费学习笔记(深入)”; 几乎所有 DOM 事件都支持冒泡( 因为 这导致一个常见误解:以为“没写 看 别靠猜,加一行 真正容易被忽略的,是捕获阶段的存在本身——它不报错、不警告、也不影响日常开发,直到你需要在某个祖先元素上“提前干预”事件时,才发现原来得把第三个参数设成 时,事件会先从 window 开始,依次经过 document、、、外层 。这个过程叫捕获阶段。
addEventListener(type, handler, true) 或 addEventListener(type, handler, { capture: true })。
addEventListener 都只响应冒泡阶段event.stopPropagation() 中断冒泡(因为冒泡还没开始) 捕获所有点击前统一做权限判断事件冒泡阶段:从目标元素到 window 的“上行路径”
后,事件会反过来,从它自己出发,逐级向上传给父 、document、window。这是默认行为,也是日常最常打交道的阶段。focus、blur、mouseenter 等少数几个不冒泡)。
event.stopPropagation() 可阻止后续冒泡,但不影响当前节点上的其他监听器执行event.stopImmediatePropagation() 还会跳过同一节点上尚未执行的其他监听器ul.addEventListener('click', e => {...}) 处理内部 )完全依赖冒泡
为什么
onclick 属性和 addEventListener 行为看起来一样?onclick="..." 和不带第三参数的 addEventListener(..., ..., false) 都绑定在冒泡阶段,且无法切换到捕获阶段。true 就没捕获”。其实捕获一直存在,只是你没监听它。
onclick 属性本质是 addEventListener('click', handler, false) 的语法糖addEventListener,按注册顺序执行;但 onclick 会被后设的覆盖addEventListener,避免隐式覆盖和阶段不可控调试时怎么确认当前在哪个阶段?
event.eventPhase:1 = 捕获中(CAPTURING_PHASE),2 = 目标本身(AT_TARGET),3 = 冒泡中(BUBBLING_PHASE)。console.log(event.eventPhase) 最直接。
eventPhase === 2 时两者都会触发(捕获先、冒泡后)event.currentTarget 区分“谁在处理”,用 event.target 看“点的是谁”——冒泡中二者经常不同touchstart)可能因浏览器优化略过部分阶段,不能假设一定完整走完true 才能接住。











