1. 事件流概述
当你在网页上的一个元素上触发一个事件(比如点击按钮),这个事件不会仅仅停留在这个元素上,而是会在整个DOM树中传播。这种传播有两个方向:从上到下(事件捕捉)和从下到上(事件冒泡)。
2. 事件捕捉(从外到内)
<div id="outer">
<div id="middle">
<button id="inner">Click Me</button>
</div>
</div>
当你点击按钮时,事件首先会从 document 开始,逐层往下传播到 div#outer、div#middle,最后到达 button#inner。这个从外向内的过程就是事件捕捉。
3. 目标阶段
当事件传播到目标元素(即你点击的按钮 button#inner)时,事件进入目标阶段。在这个阶段,事件会被目标元素处理。
4. 事件冒泡(从内到外)
在目标阶段之后,事件开始从目标元素向外传播,依次经过 div#middle、div#outer,最后回到 document。这个从内向外的过程就是事件冒泡。
假设你在 div#outer、div#middle 和 button#inner 上都绑定了点击事件处理程序,事件处理的顺序会根据你使用的是事件捕捉还是事件冒泡而不同。
- 事件捕捉(从外到内):如果你选择捕捉阶段处理事件,那么事件处理顺序是
div#outer->div#middle->button#inner。 - 事件冒泡(从内到外):如果你选择冒泡阶段处理事件,那么事件处理顺序是
button#inner->div#middle->div#outer。
如何控制事件处理阶段
addEventListener 的第三个参数用来指定是使用事件捕捉还是事件冒泡:
document.getElementById('outer').addEventListener('click', () => {
console.log('Outer div');
}, true); // true表示使用事件捕捉阶段
document.getElementById('inner').addEventListener('click', () => {
console.log('Inner button');
}, false); // false表示使用事件冒泡阶段,默认值