JavaScript事件处理核心是事件流,分捕获(document→目标前节点)、目标(事件落在触发元素)和冒泡(目标→document)三阶段;addEventListener第三参数为true表示捕获阶段监听,但目标自身不参与捕获,仅父级触发。

JavaScript 事件处理的核心不是“怎么绑函数”,而是“事件在 DOM 树里怎么走”——搞不清事件流,addEventListener 的第三个参数就永远是蒙的。
为什么 addEventListener 第三个参数设为 true 有时没反应?
因为浏览器默认只在冒泡阶段触发事件监听器,设 true 是告诉它:“我要在捕获阶段就介入”。但捕获阶段本身不触发目标元素上的监听器(除非你显式给目标也加了 true),所以常被误以为“没生效”。
- 捕获阶段:从
document→html→body→ 父div→ …… → 目标前一个父节点,**不经过目标自身** - 目标阶段:事件真正落到那个被点击/触发的元素上,此时
event.target === event.currentTarget - 冒泡阶段:从目标开始,逐层向上触发父级监听器,直到
document - 只有目标阶段和冒泡阶段会自然触发你绑定在目标元素上的监听器;捕获阶段要触发目标自身的监听器,必须单独给它也传
true
event.target 和 event.currentTarget 总分不清?
它们的区别直接暴露你是否理解事件流:前者永远是“真正被点中的那个元素”,后者是你“把事件监听器绑在了谁身上”。
- 用事件委托时,
event.target是子按钮,event.currentTarget是父容器(你绑监听器的地方) - 如果在目标元素上直接绑监听器且没阻止传播,两者在目标阶段相等;一旦事件冒泡到父级,父级的
currentTarget就是父元素,target还是原始子元素 - 别用
this替代event.currentTarget——箭头函数里this不指向绑定元素,容易出错
事件委托到底依赖哪个阶段?
事件委托完全依赖**冒泡阶段**。没有冒泡,委托就失效。
立即学习“Java免费学习笔记(深入)”;
- 你给
ul绑click,里面动态添加的li不用再单独绑定——因为点击li后,事件会冒泡到ul,你靠event.target判断是不是li即可 - 如果某个中间父元素调用了
event.stopPropagation(),委托就断了——后续父级收不到事件,ul监听器不会执行 - 表单类事件(如
focus、blur、change)默认不冒泡,不能直接委托;得用focusin/focusout这类替代方案
const container = document.getElementById('list');
container.addEventListener('click', function(e) {
if (e.target.tagName === 'LI') {
console.log('点中了列表项:', e.target.textContent);
}
});
// ✅ 正确:利用冒泡,在父容器上统一处理所有 li 的 click
// ❌ 错误:给每个 li 单独 addEventListener(尤其动态增删时易漏绑、内存泄漏)
事件流不是理论考题,是每天写交互时真实踩坑的源头:比如阻止默认行为后忘了 stopPropagation,导致父级折叠菜单意外关闭;又比如在捕获阶段绑了全局拦截,却忘了它连 document 都还没到目标就触发了。真正卡住你的,往往不是语法,而是哪一帧、哪个节点、哪个阶段,事件对象正路过谁的门口。











