javascript事件冒泡和捕获是什么?【教程】

12次阅读

事件流分捕获、目标、冒泡三阶段,addEventlistener的useCapture参数决定监听器触发阶段;stopPropagation()会终止整个事件流,无法单独阻止冒泡或捕获。

javascript事件冒泡和捕获是什么?【教程】

事件冒泡和捕获是 javaScript 事件流的两个阶段,决定事件如何在 dom 树中传播。它们不是可选“模式”,而是浏览器固有行为——你无法禁用其中一者,但可以控制监听器在哪个阶段触发。

addEventListener 的第三个参数决定监听阶段

关键在于 addEventListener 的第三个参数:useCapture。它是个布尔值,默认为 false(冒泡阶段),设为 true 则在捕获阶段触发。

  • 冒泡阶段:事件从目标元素向上逐级传到 document(如:button → div → body → html → document)
  • 捕获阶段:事件从 document 向下逐级传到目标元素(如:document → html → body → div → button)
  • 目标阶段本身既不属于纯捕获也不属于纯冒泡,但会触发所有绑定的监听器(无论 useCapture 是 true 还是 false)

事件触发顺序:捕获 → 目标 → 冒泡

一个点击事件完整流程是:先走捕获路径(从外向内),到达目标后执行目标上的监听器,再走冒泡路径(从内向外)。如果多个监听器绑在同一元素上,useCapture=true 的总在 useCapture=false 之前执行。

document.addEventListener('click', () => console.log('document capture'), true); document.body.addEventListener('click', () => console.log('body capture'), true); document.body.addEventListener('click', () => console.log('body bubble'), false); document.getElementById('btn').addEventListener('click', () => console.log('button target'), false); document.getElementById('btn').addEventListener('click', () => console.log('button target again'), true);

点击按钮时输出顺序为:document capturebody capturebutton target againbutton targetbody bubble

立即学习Java免费学习笔记(深入)”;

stopPropagation() 会同时阻断捕获和冒泡

event.stopPropagation() 并不区分阶段——它一旦被调用,整个事件流立即终止,后续所有阶段(包括同级其他监听器)都不会执行。

  • 在捕获阶段调用,后续捕获监听器、目标阶段、冒泡阶段全跳过
  • 在目标阶段调用,冒泡阶段直接中断;但注意:同一元素上 useCapture=trueuseCapture=false 的监听器都已执行完毕,因为目标阶段是共享的
  • 想只阻止冒泡而保留捕获?做不到。浏览器不提供“仅停冒泡”或“仅停捕获”的 API

日常开发中捕获阶段极少显式使用

绝大多数业务逻辑依赖冒泡(比如委托ul 处理所有 li 点击),所以 useCapture 很少写成 true。唯一常见例外是全局防误触或早期拦截:

  • document 捕获阶段监听 click,快速判断是否点在某个弹窗外部,然后关闭它
  • 某些 ui 库在根容器用捕获监听键盘事件,确保 Esc 总能被最早捕获并处理
  • 注意:react 的合成事件默认只支持冒泡,onMouseDownCapture 这类带 Capture 后缀的 props 才进入捕获阶段

真正容易出问题的是嵌套监听器 + stopPropagation() + 混用 useCapture,这时候事件流走向很难靠直觉推断,必须动手打印验证。

text=ZqhQzanResources