事件冒泡和捕获机制

理解 DOM 事件的冒泡和捕获阶段,以及 addEventListener 的第三个参数

问题

当嵌套元素都绑定了同一事件时,事件的触发顺序是怎样的?

<div id="outer">
    <p id="inner">Click me!</p>
</div>

如果 divp 都绑定了 click 事件,点击 p 时哪个处理函数会先执行?

解答

事件冒泡(Event Bubbling)

微软提出的事件流机制。事件从最内层元素开始触发,逐层向上传播到 document

点击 p 元素的触发顺序:

p → div → body → html → document

事件捕获(Event Capturing)

网景提出的事件流机制。事件从最外层开始触发,逐层向下传播到目标元素。

点击 p 元素的触发顺序:

document → html → body → div → p

W3C 标准:先捕获后冒泡

W3C 采用折中方案,事件传播分为三个阶段:

  1. 捕获阶段:从 document 到目标元素
  2. 目标阶段:到达目标元素
  3. 冒泡阶段:从目标元素到 document

addEventListener 的第三个参数

element.addEventListener(event, function, useCapture)
  • event:事件类型(如 'click'
  • function:事件处理函数
  • useCapture:布尔值,默认 false
    • false:在冒泡阶段调用处理函数
    • true:在捕获阶段调用处理函数

示例:

const outer = document.getElementById('outer');
const inner = document.getElementById('inner');

// 冒泡阶段触发
outer.addEventListener('click', () => console.log('outer 冒泡'), false);
inner.addEventListener('click', () => console.log('inner 冒泡'), false);

// 捕获阶段触发
outer.addEventListener('click', () => console.log('outer 捕获'), true);
inner.addEventListener('click', () => console.log('inner 捕获'), true);

// 点击 inner 输出顺序:
// outer 捕获 → inner 捕获 → inner 冒泡 → outer 冒泡

关键点

  • 冒泡:事件从内向外传播(p → div → body → document)
  • 捕获:事件从外向内传播(document → body → div → p)
  • W3C 标准:先捕获后冒泡,共三个阶段
  • addEventListener 第三个参数控制在哪个阶段触发,默认 false(冒泡阶段)
  • 可以用 event.stopPropagation() 阻止事件继续传播