Appearance
目录
1. 核心心智模型
当你在网页上点击一个元素时,这个"点击事件"并不仅仅发生在该元素上。它经历了一个完整的旅程,这个旅程被称为 DOM 事件流。
想象一下一个三层嵌套的盒子:div (外层) > p (中层) > span (内层)。当你点击最里面的 span 时:
- 捕获阶段: 浏览器会从最外层的祖先 window 开始,像一个"指挥官"下达命令一样,逐级向下"探查",经过 document、
<html>、<body>、div、p,最终到达你点击的目标 span。这个从外到内的过程就是捕获阶段。 - 目标阶段: 事件到达了它的最终目的地——你实际点击的 span 元素。事件在这里被触发。
- 冒泡阶段: 事件完成任务后,开始"汇报工作"。它会从 span 开始,逐级向上"冒泡",经过 p、div,一直到 window。这个从内到外的过程就是冒泡阶段。
一句话总结:事件先从外到内"潜入"(捕获),到达目标后,再从内到外"浮出"(冒泡)。
默认情况下,我们用 addEventListener 添加的监听器只在 冒泡阶段 执行。
2. 示例:在控制台直观展示事件流
让我们用代码来直观地看到这个完整的路径。
HTML 结构:
html
<div class="grandparent">
Grandparent
<div class="parent">
Parent
<div class="child">Child</div>
</div>
</div>CSS (仅为视觉效果):
css
div {
padding: 30px;
border: 2px solid #666;
text-align: center;
font-family: sans-serif;
}
.grandparent { background-color: #fdd; }
.parent { background-color: #dfd; }
.child { background-color: #ddf; }JavaScript 实现:
我们将为每一个 div 都添加两个监听器:
- 一个在捕获阶段触发 (
{ capture: true }) - 一个在冒泡阶段触发 (默认)
javascript
const grandparent = document.querySelector('.grandparent');
const parent = document.querySelector('.parent');
const child = document.querySelector('.child');
// --- 捕获阶段监听器 ---
grandparent.addEventListener('click', () => {
console.log('Grandparent - 捕获阶段');
}, { capture: true });
parent.addEventListener('click', () => {
console.log('Parent - 捕获阶段');
}, { capture: true });
child.addEventListener('click', () => {
console.log('Child - 捕获阶段 (也会在目标阶段触发)');
}, { capture: true });
// --- 冒泡阶段监听器 ---
grandparent.addEventListener('click', () => {
console.log('Grandparent - 冒泡阶段');
});
parent.addEventListener('click', () => {
console.log('Parent - 冒泡阶段');
});
child.addEventListener('click', () => {
console.log('Child - 冒泡阶段');
});运行与分析:
现在,打开浏览器的开发者工具,点击最内层的蓝色 Child 区域。你会在控制台看到以下输出:
// ↓ 从外到内(捕获阶段)
Grandparent - 捕获阶段
Parent - 捕获阶段
Child - 捕获阶段 (也会在目标阶段触发)
// ↓ 从内到外(冒泡阶段)
Child - 冒泡阶段
Parent - 冒泡阶段
Grandparent - 冒泡阶段结果分析:
- 事件开始下沉: 点击发生后,事件流从 grandparent 开始,触发了它的捕获监听器。
- 继续下沉: 事件流到达 parent,触发了它的捕获监听器。
- 到达目标: 事件流到达 child。在目标元素上,监听器触发的顺序是按代码注册的顺序,所以先触发了捕获监听器,然后是冒泡监听器。
- 事件开始上浮: 完成目标阶段后,事件开始冒泡,从 child 上浮到 parent,触发了 parent 的冒泡监听器。
- 继续上浮: 事件继续上浮到 grandparent,触发了它的冒泡监听器,旅程结束。
通过这个简单的实验,事件流的完整"V"字形路径被清晰地展现在我们面前。理解这个模型是掌握事件委托、阻止事件传播等高级技巧的基础。