04. 浏览器事件传递模型详解
1. 事件流三阶段模型
现代浏览器采用 W3C 定义的三级事件流模型,其传递过程分为三个阶段:
1.1 捕获阶段 (Capture Phase)
事件从 window
对象开始,逐级向下传递到目标元素。计算公式可表示为:
示例代码展示捕获阶段监听:
javascript
document.querySelector('#outer').addEventListener(
'click',
() => console.log('捕获阶段触发'),
true // 第三个参数表示使用捕获模式
);
1.2 目标阶段 (Target Phase)
事件到达目标元素时触发,此时无论注册为捕获还是冒泡模式的事件监听器都会执行。若目标元素有多个监听器,按注册顺序执行:
javascript
element.addEventListener('click', handler1);
element.addEventListener('click', handler2); // handler1 先于 handler2 执行
1.3 冒泡阶段 (Bubble Phase)
事件从目标元素逐级向上回溯到 window
对象。大多数原生事件(如 click
)支持冒泡,但某些事件(如 focus
)不冒泡:
2. 历史事件模型演进
2.1 DOM0 级事件模型 (1996)
特征:
- 通过元素属性绑定事件
- 仅支持冒泡阶段
- 同一事件只能绑定一个处理器
html
<button onclick="console.log('DOM0 事件')">点击</button>
2.2 IE 事件模型 (1996-2001)
特征:
- 使用
attachEvent/detachEvent
- 不支持捕获阶段
- 事件名称带
on
前缀 this
指向 window 对象
javascript
element.attachEvent('onclick', function() {
console.log('IE 事件模型');
});
2.3 DOM2 级事件模型 (2000)
里程碑式改进:
- 引入
addEventListener/removeEventListener
- 支持捕获/冒泡双阶段
- 支持多个事件监听器
- 规范了 Event 对象
javascript
element.addEventListener('click', handler, {
capture: true, // 捕获阶段
once: true, // 单次触发
passive: true // 不阻止默认行为
});
3. 关键传播控制方法
3.1 事件传播阻断
javascript
event.stopPropagation(); // 阻止继续传播
event.stopImmediatePropagation(); // 立即停止所有监听器
3.2 默认行为阻止
javascript
event.preventDefault(); // 阻止表单提交等默认行为
4. 现代事件委托模式
利用冒泡机制实现高效事件处理:
javascript
document.getElementById('list').addEventListener('click', (e) => {
if(e.target.matches('li.item')) {
console.log('点击项目:', e.target.dataset.id);
}
});
5. 事件类型传播特性
事件类型 | 冒泡支持 | 捕获支持 | 取消能力 |
---|---|---|---|
click | ✔ | ✔ | ✔ |
focus | ✘ | ✔ | ✘ |
mouseenter | ✘ | ✘ | ✔ |
scroll | ✔ (Chrome 63+) | ✔ | ✘ |
6. 性能优化建议
使用被动事件监听器提升滚动性能:
javascriptwindow.addEventListener('wheel', handler, { passive: true });
避免在捕获阶段执行耗时操作:
text捕获阶段 -> 快速通过 目标阶段 -> 核心处理 冒泡阶段 -> 响应式处理
及时移除无用事件监听器防止内存泄漏
该事件流模型经过 20 余年演进,已成为现代 Web 开发的基石。理解其工作原理对实现精确的事件控制、性能优化和复杂交互开发至关重要。