Appearance
你以为事件只是绑定了就完事?其实它背后还有“来龙去脉”!
🔍 什么是事件传播?
当你在网页中点击一个按钮时,这个“事件”并不会直接只作用于这个按钮,而是沿着 DOM 树进行传播。这个传播过程有三个阶段:
📶 事件传播的三个阶段
捕获阶段(Capturing Phase):事件从
window
一路向下传递到目标元素。目标阶段(Target Phase):事件到达真正被点击的目标元素。
冒泡阶段(Bubbling Phase):事件从目标元素向上传递到
window
。
🔁 示例结构
html
<body>
<div id="outer">
<div id="inner">
<button id="btn">Click me</button>
</div>
</div>
</body>
点击 #btn
后的事件传播顺序如下:
window ↓
document ↓
html ↓
body ↓
#outer ↓
#inner ↓
#btn ← 目标阶段
#inner ↑
#outer ↑
body ↑
html ↑
document ↑
window ↑
🧪 示例代码:冒泡与捕获监听对比
js
// 捕获阶段
outer.addEventListener('click', () => {
console.log('outer capture');
}, true);
// 冒泡阶段
outer.addEventListener('click', () => {
console.log('outer bubble');
});
输出顺序:
outer capture
outer bubble
🧠 关键点记忆
|比较项|捕获(Capturing)|冒泡(Bubbling)| |||| |方向|从外到内(顶层 → 目标)|从内到外(目标 → 顶层)| |是否默认启用|❌ 否(需设置为第三个参数 true
)|✅ 是| |使用场景|特定顺序控制,如拦截早期事件|最常见,用于事件委托| |是否可中断|否(不能中断捕获本身)|✅ event.stopPropagation()
| |常配合|window、document 捕获|事件委托、组件冒泡|
🧯 如何中断传播?
js
// 阻止继续冒泡
event.stopPropagation();
// 阻止默认行为(如 <a> 跳转)
event.preventDefault();
🎯 实战应用:事件委托
js
document.getElementById('list').addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
console.log('点击了某个列表项');
}
});
使用冒泡机制,不必给每个子元素绑定事件
适用于动态添加元素的情况
🧩 总结一句话:
事件是从外往内捕获,从内往外冒泡的。默认是冒泡监听,要捕获得手动指定。