Skip to content

一张通俗易懂的「事件传播顺序图」,讲清楚 JavaScript 中 捕获、目标、冒泡 三个阶段,还有 addEventListener 第三个参数 capture 的真实作用。


🎯 事件传播三阶段图(事件流)

HTML 结构(从外到内):

<div id="outer">
  <div id="middle">
    <button id="inner">点击我</button>
  </div>
</div>

假设你点击了按钮 #inner,事件传播顺序如下:

(1)捕获阶段(Capture Phase):
document

html

body

#outer

#middle

#inner
  • 从最外层往里走
  • 如果你用:addEventListener("click", fn, true) 就会在捕获阶段触发

(2)目标阶段(Target Phase):
#inner
  • 到达你点击的真正目标
  • 这里会执行所有在 #inner 上绑定的监听器(无论是不是捕获阶段绑定的)

(3)冒泡阶段(Bubble Phase):
#inner

#middle

#outer

body

html

document
  • 从目标一路向外冒泡回去
  • 如果你用:addEventListener("click", fn, false)(默认) 就会在冒泡阶段触发

🧪 图示(手写版)

text
点击 #inner 后执行顺序(监听都加了):

🔽 捕获阶段(capture: true):
document
 → html
   → body
     → #outer
       → #middle
         → #inner

🎯 目标阶段:
#inner

🔼 冒泡阶段(capture: false):
#inner
 ← #middle
   ← #outer
     ← body
       ← html
         ← document

📌 一句话总结:

第三参数意思触发阶段
true捕获阶段触发(外→内)捕获
false默认,冒泡阶段触发(内→外)冒泡
{ once: true }只执行一次就解绑常用于限时点击

✅ 推荐做法

  • 日常开发 99% 用的是冒泡阶段(默认)
  • 特殊场景(比如拖动时想阻止外层滚动)可以用捕获阶段
  • 嵌套结构中阻止传播用:
    • event.stopPropagation() 阻止冒泡
    • event.stopImmediatePropagation() 阻止当前元素后续监听器执行