React 事件机制通俗版:从捕获到冒泡,搞懂就能吹一年!

315 阅读3分钟

前端人写 React,总绕不开事件绑定,但你真的懂 React 事件背后的捕获目标冒泡三大阶段吗?
今天咱们就把这套DOM 2 事件流模型掰开了揉碎了,从浏览器到 React,讲到你怀疑自己以前学的是假冒泡。


一、先来点背景故事:谁发明了事件流?

最早的浏览器事件处理只有冒泡阶段,后来 DOM 2 标准拍了拍桌子:“咱搞个正经流程:捕获 → 目标 → 冒泡,一套三步走,显得专业。”

于是就有了现在我们熟悉的事件流(Event Flow)

  • 捕获阶段:从 documentwindow 开始,顺着 DOM 树一路向下找目标元素。
  • 目标阶段:事件到达 event.target,干活!
  • 冒泡阶段:事情干完了,事件原路返回,冒泡到根。

二、三大阶段长啥样?举个栗子!

假如你点了一个按钮 <button>,实际流程像送快递:

1️⃣ 捕获阶段
快递小哥从公司出发(document),一路往你家(按钮)走。沿路的小区门卫、楼管(父元素)可以拦住他(注册了捕获监听器)。

2️⃣ 目标阶段
快递小哥按门铃(event.target),你(按钮)签收(执行目标阶段监听器)。

3️⃣ 冒泡阶段
快递小哥下楼出小区(事件冒泡),门卫还能再拦他聊两句(冒泡监听器执行)。


三、来点代码验证下

<div id="outer">
  <button id="btn">点我啊</button>
</div>
const outer = document.getElementById('outer');
const btn = document.getElementById('btn');

outer.addEventListener(
  'click',
  () => console.log('外层 div - 捕获阶段'),
  true // 捕获阶段
);

outer.addEventListener(
  'click',
  () => console.log('外层 div - 冒泡阶段')
);

btn.addEventListener('click', () => console.log('按钮 - 目标阶段'));

当你点击按钮时,打印顺序必然是:

外层 div - 捕获阶段
按钮 - 目标阶段
外层 div - 冒泡阶段

完美验证:先捕获、到目标、再冒泡。


四、React 的合成事件是怎么回事?

这里很多同学会疑惑:

为啥 React 不直接用原生事件?

答案很简单:React 实现了合成事件(SyntheticEvent)
它做了这几件事:

  • 把所有事件都挂到根节点(比如 document),只绑定一次,节省内存。
  • 自己管理事件池(事件对象复用),提高性能。
  • 兼容不同浏览器事件差异。
  • 自动在冒泡阶段触发,不用你关心 useCapture

所以在 React 中,你写:

<button onClick={() => console.log('hi')} />

背后其实就是在根节点监听 click,然后根据冒泡阶段匹配到你的按钮,执行回调。


五、必须掌握的两个宝:阻止冒泡 & 阻止默认

前端事件的标配小招式,写页面必用:

  • event.stopPropagation()
    → 不让事件继续冒泡,比如点击弹窗内部阻止冒泡,外层就监听不到了。
  • event.preventDefault()
    → 阻止默认行为,比如点击 <a> 不跳转,提交 <form> 不刷新。

六、事件委托:面试必考题,日常也真香

事件委托就是把一堆子元素的事件交给父元素处理,靠的就是冒泡阶段。

看个 React/原生都一样的经典例子:

<ul id="list">
  <li>苹果</li>
  <li>香蕉</li>
  <li>哈密瓜</li>
</ul>
document.getElementById('list').addEventListener('click', (e) => {
  console.log('你点击了:', e.target.innerText);
});

点击任意 <li>,父元素 <ul> 都能通过 event.target 精准知道你点了谁。
这就是事件委托的核心:一个监听器,搞定一群孩子。


⚠ 注意:event.targetevent.currentTarget

  • event.target:触发事件的实际元素(谁被点了)。
  • event.currentTarget:绑定监听器的那个元素(谁监听的)。

例子:

<ul id="list">
  <li><span>点我</span></li>
</ul>

点击 <span>event.target<span>event.currentTarget<ul>
小心别搞混,不然委托经常写崩。


总结一句话

前端事件流 = 捕获 + 目标 + 冒泡。
React 合成事件默认只在冒泡阶段触发。
阻止冒泡、阻止默认、事件委托这仨,写 React 必备。
下回再有人问你:

“React 的事件机制你会吗?”
请把这篇文章拍他脸上,转身就去吹牛!


结尾互动

看完这篇,事件流是不是终于没那么悬了?
如果还有没搞懂的地方,评论区见,我随时帮你把快递再送一遍!


如果觉得有用,记得点个赞 👍+ 收藏 ⭐
掘金不迷路,咱们下篇见!✨