皮肤模式
一张通俗易懂的「事件传播顺序图」,讲清楚 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()
阻止当前元素后续监听器执行