一、事件流是什么?

事件流就像你点击网页按钮时,浏览器处理点击事件的 “传播路径”。它决定了事件从触发到结束的完整过程,分为三个阶段:捕获阶段 → 目标阶段 → 冒泡阶段。

二、举个现实例子 🌰

想象你网购了一个快递:

捕获阶段:快递从北京仓库(顶层)出发,层层向下分发到省 → 市 → 区 → 街道(你的家)。

目标阶段:快递员敲你家门(触发事件的目标元素)。

冒泡阶段:你签收后,快递信息反向向上通知:街道 → 区 → 市 → 省 → 仓库(顶层)。

这就是事件流的完整过程!

三、事件流的三个阶段

1. 捕获阶段(Capture Phase)

方向:从最外层父元素(如 window)向目标元素 层层向下传递。

作用:类似快递从总部派送到你家,可以中途拦截事件。

代码控制:通过 addEventListener 的第三个参数设为 true 监听捕获阶段:

parent.addEventListener('click', function() {

console.log('捕获阶段:父元素被触发');

}, true); // true 表示监听捕获阶段

2. 目标阶段(Target Phase)

作用:事件到达你实际点击的元素(如按钮)。

细节:事件在目标元素上触发,无论是冒泡还是捕获阶段注册的监听器都会执行。

3. 冒泡阶段(Bubble Phase)

方向:从目标元素向上 层层冒泡 到最外层父元素。

作用:类似快递签收后,信息回传到总部。

默认监听:addEventListener 默认监听冒泡阶段:

child.addEventListener('click', function() {

console.log('冒泡阶段:子元素被触发');

}); // 第三个参数默认是 false(监听冒泡)

四、实际代码演示

假设 HTML 结构如下:

当你点击按钮时,事件流的执行顺序是:

捕获阶段:爷爷 → 爸爸 → 儿子

目标阶段:儿子

冒泡阶段:儿子 → 爸爸 → 爷爷

1.示例代码1

外层

中层

内层

2.示例代码2

事件流示例

爷爷

爸爸

儿子

五、事件流的实际应用

1. 事件委托(Event Delegation)

场景:动态添加的子元素(如列表项)需要绑定事件。

原理:利用冒泡阶段,直接在父元素上监听事件。

⑴.通俗理解

想象你开了一家超市,有很多货架(子元素)。如果每个货架都要安排一个员工(事件监听器)来处理顾客的咨询,会很浪费人力(内存)。

事件委托就像让一个经理(父元素)站在入口统一处理所有货架的咨询。当顾客(事件)在某个货架咨询时,问题会 “冒泡” 到经理那里,经理根据具体货架(event.target)来处理问题。这样既节省人力,又方便管理新添加的货架。

⑵.核心原理

事件冒泡:子元素触发事件后,事件会逐级向上传递到父元素。判断目标:父元素通过 event.target 找到真正触发事件的子元素,从而执行对应的操作。

⑶.代码示例解析

  • 列表项 1
  • 列表项 2
  • 列表项 3

父元素监听事件:

我们只给 ul(父元素)绑定了一个点击事件监听器,而不是给每个 li(子元素)绑定。

通过 event.target 判断目标:

当点击某个 li 时,事件会冒泡到 ul。event.target 会指向被点击的 li,因此 if (event.target.tagName === 'LI') 能精准识别点击的是哪个 li。

动态添加元素自动支持:

点击 “添加列表项” 按钮时,新的 li 会被添加到 ul 中。由于 ul 已经监听了点击事件,新的 li 无需额外绑定事件,自动生效。

⑷.事件委托的优点

节省内存:只需给父元素绑定一次事件,避免为每个子元素单独绑定。动态元素兼容:新增的子元素自动继承父元素的事件监听,无需重新绑定。简化代码:集中处理同类元素的事件,代码更简洁。

2.阻止事件传播

有时候,我们希望某个元素的事件不会影响到其父元素,这时可以使用 stopPropagation() 方法来阻止事件冒泡。

阻止事件传播示例

外层元素

内层元素

3. 阻止默认行为

方法:e.preventDefault() 阻止元素的默认行为(如链接跳转)。

阻止链接默认跳转

点击我,不会跳转

六、总结

事件流三阶段:捕获 → 目标 → 冒泡(像快递的派送和回传)。

控制监听阶段:通过 addEventListener 的第三个参数选择监听捕获或冒泡。

灵活应用:事件委托、阻止传播等技巧能大幅简化代码逻辑。