Skip to content

04. 浏览器事件传递模型详解

1. 事件流三阶段模型

现代浏览器采用 W3C 定义的三级事件流模型,其传递过程分为三个阶段:

1.1 捕获阶段 (Capture Phase)

事件从 window 对象开始,逐级向下传递到目标元素。计算公式可表示为:

windowdocumentparentNodetarget\text{window} \rightarrow document \rightarrow \cdots \rightarrow \text{parentNode} \rightarrow \text{target}

示例代码展示捕获阶段监听:

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)不冒泡:

targetparentNodedocumentwindow\text{target} \rightarrow \text{parentNode} \rightarrow \cdots \rightarrow document \rightarrow window

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. 性能优化建议

  1. 使用被动事件监听器提升滚动性能:

    javascript
    window.addEventListener('wheel', handler, { passive: true });
  2. 避免在捕获阶段执行耗时操作:

    text
    捕获阶段 -> 快速通过
    目标阶段 -> 核心处理
    冒泡阶段 -> 响应式处理
  3. 及时移除无用事件监听器防止内存泄漏

    该事件流模型经过 20 余年演进,已成为现代 Web 开发的基石。理解其工作原理对实现精确的事件控制、性能优化和复杂交互开发至关重要。