event.target 是实际被点击的元素,event.currentTarget 是事件监听器绑定的元素;事件冒泡时若监听器在祖先元素上,则二者不同,如事件委托中点击 li 时 target 是 li 或其子节点,currentTarget 始终是 ul。

event.target 指的是**实际被点击的元素**,而 event.currentTarget 指的是**当前事件监听器所绑定的元素**。两者在事件冒泡场景下最常出现差异——比如给父容器绑了点击事件,但用户点的是里面的一个按钮,这时 target 是按钮,currentTarget 是父容器。
什么时候 target 和 currentTarget 不一样?
当事件发生后沿 DOM 向上冒泡,且监听器注册在祖先元素上时,就会出现差异:
- 用户点击子元素(如 span、button、img),该子元素就是 target
- 如果监听器写在它的父级(如 div、section)上,那个父级就是 currentTarget
- 若监听器直接写在被点击的元素上(无冒泡路径),则 target === currentTarget
一个典型例子:委托点击处理
用事件委托时,你往往只在 ul 上监听 click,却要判断点中的是哪个 li:
HTML:- 苹果
- 香蕉
- 橙子
document.getElementById('list').addEventListener('click', function(e) {
console.log('target:', e.target); // 可能是 li,也可能是 li 里的文字节点
console.log('currentTarget:', e.currentTarget); // 总是 ul#list
});
注意:e.target 可能不是 li(比如用户点的是 li 里的文本,target 就是 Text 节点),所以常用 e.target.closest('li') 安全获取目标列表项。
如何安全地获取真正想操作的元素?
别直接依赖 e.target.tagName,尤其在结构复杂或含内联内容时:
- 用
e.target.closest('selector')向上查找最近匹配的祖先(推荐) - 用
e.target === e.currentTarget判断是否是直接触发(可用于阻止冒泡逻辑) - 必要时检查
e.target.nodeType === Node.ELEMENT_NODE排除文本/注释节点
一个小技巧:调试时快速验证
在事件回调里加一句:console.log({ target: e.target, currentTarget: e.currentTarget });
然后点几下不同位置,对比输出,很快就能建立直观理解。

















