2026-10-30 21:09:48
JavaScript 中的事件捕获与冒泡是事件流的核心机制,用于定义事件在 DOM 树中的传播顺序。默认情况下事件按冒泡顺序执行,但可通过参数显式启用捕获阶段。
一、事件流的基本概念事件流描述了事件在 DOM 树中的传播路径,分为三个阶段:
执行顺序
捕获阶段:由外向内触发,顺序为父元素 → 子元素。
冒泡阶段:由内向外触发,顺序为子元素 → 父元素。
示例:点击 inner 元素时,若所有监听器均启用捕获,输出顺序为:outer捕获 → middle捕获 → inner捕获。
浏览器兼容性
IE < 9:仅支持冒泡阶段,不支持捕获。
现代浏览器(IE9+、Chrome、Firefox、Safari):同时支持捕获和冒泡。
监听器参数
通过 addEventListener 的第三个参数控制阶段:
true:在捕获阶段触发。
false(默认):在冒泡阶段触发。
以下代码演示了捕获与冒泡的混合使用:
<div id="outer"> <div id="middle"> <div id="inner"></div> </div></div><script> // 捕获阶段监听器 outer.addEventListener('click', () => console.log('outer捕获'), true); middle.addEventListener('click', () => console.log('middle捕获'), true); inner.addEventListener('click', () => console.log('inner捕获'), true); // 冒泡阶段监听器 inner.addEventListener('click', () => console.log('inner冒泡'), false); middle.addEventListener('click', () => console.log('middle冒泡'), false); outer.addEventListener('click', () => console.log('outer冒泡'), false);</script>输出结果:
event.stopPropagation()
阻止事件在捕获或冒泡阶段的进一步传播。
示例:
在 middle捕获 中调用 event.stopPropagation(),则 inner捕获 不会触发。
在 middle冒泡 中调用,则 outer冒泡 不会触发。
event.stopImmediatePropagation()
阻止同一元素上其他监听器的执行(包括捕获和冒泡阶段)。
注意事项
阻止传播不会阻止目标阶段的事件触发。
在需要完全隔离事件时使用,但过度使用可能导致代码难以维护。
事件委托
利用冒泡机制,在父元素上统一处理子元素事件,减少监听器数量。
示例:
document.getElementById('list').addEventListener('click', (e) => { if (e.target.tagName === 'LI') { console.log('点击了列表项:', e.target.textContent); }});自定义右键菜单
在 document 上阻止默认冒泡行为,避免浏览器原生菜单干扰。
表单验证
在外层容器捕获提交事件,统一验证后再决定是否冒泡到表单提交。
为什么事件有时会触发多次?
可能因嵌套元素监听同类事件,且未正确阻止传播导致重复触发。
如何仅触发捕获或冒泡?
通过 addEventListener 的第三个参数显式指定阶段,避免混合使用。
IE8 及以下如何处理?
仅支持冒泡,需通过 attachEvent 添加监听器(无捕获阶段)。