事件冒泡与捕获
DOM事件传播分为三个阶段:捕获阶段、目标阶段、冒泡阶段。
事件流机制
JavaScript
捕获阶段(从外到内)
↓
window → document → html → body → ... → 目标元素
↓
目标阶段
↓
window ← document ← html ← body ← ... ← 目标元素
↑
冒泡阶段(从内到外)
冒泡阶段
事件从目标元素向上传播到祖先元素:
JavaScript
// HTML: <div id="outer"><div id="inner">点击</div></div>
outer.addEventListener('click', () => {
console.log('outer');
});
inner.addEventListener('click', () => {
console.log('inner');
});
// 点击inner,输出: inner → outer
捕获阶段
事件从祖先元素向下传播到目标元素:
JavaScript
outer.addEventListener('click', () => {
console.log('outer捕获');
}, true); // 第三个参数为true
inner.addEventListener('click', () => {
console.log('inner');
});
// 点击inner,输出: outer捕获 → inner
完整事件流
JavaScript
outer.addEventListener('click', () => {
console.log('outer捕获');
}, true);
outer.addEventListener('click', () => {
console.log('outer冒泡');
}, false);
inner.addEventListener('click', () => {
console.log('inner');
});
// 点击inner输出: outer捕获 → inner → outer冒泡
阻止事件传播
stopPropagation
阻止事件继续传播(捕获或冒泡):
JavaScript
inner.addEventListener('click', (e) => {
e.stopPropagation();
console.log('inner');
});
// outer不会收到事件
stopImmediatePropagation
阻止事件传播且阻止当前元素的其他监听器:
JavaScript
inner.addEventListener('click', (e) => {
e.stopImmediatePropagation();
});
inner.addEventListener('click', () => {
// 不会被触发
});
事件监听时机对比
| 参数值 | 触发阶段 | 执行顺序 |
|---|---|---|
| false/省略 | 冒泡阶段 | 目标 → 外层 |
| true | 捕获阶段 | 外层 → 目标 |
注意:目标元素上的事件监听器,无论捕获还是冒泡,都按注册顺序执行。
实际应用
捕获阶段常用于事件拦截:
JavaScript
// 在外层拦截并阻止事件到达内层
document.addEventListener('click', (e) => {
if (e.target.matches('.disabled')) {
e.stopPropagation();
}
}, true);
冒泡阶段常用于事件委托:
text
// 利用冒泡在父元素统一处理
ul.addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
console.log(e.target.textContent);
}
});
要点总结
- 事件流三阶段:捕获 → 目标 → 冒泡
- 默认在冒泡阶段触发,设置
true在捕获阶段触发 stopPropagation阻止事件继续传播- 目标元素上的监听器按注册顺序执行
- 利用捕获可实现事件拦截,利用冒泡可实现事件委托
📝 发现内容有误?点击此处直接编辑