前端人写 React,总绕不开事件绑定,但你真的懂 React 事件背后的捕获、目标、冒泡三大阶段吗?
今天咱们就把这套DOM 2 事件流模型掰开了揉碎了,从浏览器到 React,讲到你怀疑自己以前学的是假冒泡。
一、先来点背景故事:谁发明了事件流?
最早的浏览器事件处理只有冒泡阶段,后来 DOM 2 标准拍了拍桌子:“咱搞个正经流程:捕获 → 目标 → 冒泡,一套三步走,显得专业。”
于是就有了现在我们熟悉的事件流(Event Flow)
- 捕获阶段:从
document或window开始,顺着 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.target ≠ event.currentTarget
event.target:触发事件的实际元素(谁被点了)。event.currentTarget:绑定监听器的那个元素(谁监听的)。
例子:
<ul id="list">
<li><span>点我</span></li>
</ul>
点击 <span>,event.target 是 <span>,event.currentTarget 是 <ul>。
小心别搞混,不然委托经常写崩。
总结一句话
前端事件流 = 捕获 + 目标 + 冒泡。
React 合成事件默认只在冒泡阶段触发。
阻止冒泡、阻止默认、事件委托这仨,写 React 必备。
下回再有人问你:
“React 的事件机制你会吗?”
请把这篇文章拍他脸上,转身就去吹牛!
结尾互动
看完这篇,事件流是不是终于没那么悬了?
如果还有没搞懂的地方,评论区见,我随时帮你把快递再送一遍!
如果觉得有用,记得点个赞 👍+ 收藏 ⭐
掘金不迷路,咱们下篇见!✨