你以为事件只是绑定了就完事?其实它背后还有“来龙去脉”!
🔍 什么是事件传播?
当你在网页中点击一个按钮时,这个“事件”并不会直接只作用于这个按钮,而是沿着 DOM 树进行传播。这个传播过程有三个阶段:
📶 事件传播的三个阶段
-
捕获阶段(Capturing Phase):事件从
window
一路向下传递到目标元素。 -
目标阶段(Target Phase):事件到达真正被点击的目标元素。
-
冒泡阶段(Bubbling Phase):事件从目标元素向上传递到
window
。
🔁 示例结构
<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 ↑
🧪 示例代码:冒泡与捕获监听对比
// 捕获阶段
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 捕获 | 事件委托、组件冒泡 |
🧯 如何中断传播?
// 阻止继续冒泡
event.stopPropagation();
// 阻止默认行为(如 <a> 跳转)
event.preventDefault();
🎯 实战应用:事件委托
document.getElementById('list').addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
console.log('点击了某个列表项');
}
});
-
使用冒泡机制,不必给每个子元素绑定事件
-
适用于动态添加元素的情况
🧩 总结一句话:
事件是从外往内捕获,从内往外冒泡的。默认是冒泡监听,要捕获得手动指定。