掌握事件传播关键在于理解三阶段路径:捕获(window→目标父级)、目标(仅目标元素)、冒泡(目标→window);常用stopPropagation()阻冒泡、preventDefault()阻默认行为;事件委托依赖冒泡,用event.target识别真实点击元素。

掌握事件捕获与冒泡,关键不是死记阶段名称,而是理解“事件在DOM树里怎么走、在哪能拦、为什么这么设计”。它不难,但容易因默认行为和监听器注册方式混淆而踩坑。
搞清事件传播的三步真实路径
点击一个嵌套结构中的最内层元素(比如 点我),事件实际经历:
-
捕获阶段:从
window→document→→→→,但不会进入目标元素自身();- 目标阶段:停在
上,执行它绑定的所有监听器(无论useCapture是true还是false);- 冒泡阶段:从
→→→→document→window,逐层向上触发useCapture: false的监听器。动手验证比看图更重要
写一段可运行的代码,三行就足够:
- 给
div、p、span都加click监听器; - 每个监听器里打印
event.eventPhase(1=捕获,2=目标,3=冒泡)和event.currentTarget.id; - 再分别用
{capture: true}和{capture: false}注册,对比输出顺序。
你会直观看到:捕获监听器先执行(从外往内),目标监听器紧随其后,冒泡监听器最后执行(从内往外)——整个链条清晰可测。
真正要用到的只有两个控制点
日常开发中,90% 的需求只涉及这两个操作:
-
阻止冒泡:调用
event.stopPropagation(),适合“子元素事件不该影响父逻辑”的场景,比如下拉菜单点击内部选项时,防止点击穿透关闭菜单; -
阻止默认行为:调用
event.preventDefault(),比如表单提交前校验失败,就拦住页面跳转; - 慎用
stopImmediatePropagation():它会连同级其他监听器也一起拦掉,调试时容易误判是谁没执行。
事件委托是冒泡的典型实战价值
不需要给每个按钮单独绑
click,只需在它们的公共父容器上监听一次,然后用event.target判断点击的是哪个子元素:- 优势明显:动态添加的按钮自动生效、内存占用低、绑定代码集中;
- 关键细节:确保父容器有明确高度/宽度可点击,且子元素没有
pointer-events: none; - 常见错误:用
this或event.currentTarget当作被点击元素——其实它们是父容器,真目标永远是event.target。
- 目标阶段:停在











