注册
web

event.currentTarget 、event.target 傻傻分不清楚?

在前端开发中,事件处理是交互逻辑的核心。但你是否会遇到这样的困惑:绑定事件时明明用的是父元素,触发时却总获取到子元素的信息?或是想优化大量子元素的事件绑定,却不知从何下手?


这一切的答案,都藏在 event.currentTarget和 event.target这对“双胞胎”属性里。


一、核心概念:谁在触发?谁在处理?


要理解这两个属性,首先需要明确事件流的基本概念。当用户与页面交互(如点击)时,事件会经历 ​捕获阶段 → 目标阶段 → 冒泡阶段​ 传播。而 event.currentTarget和 event.target的差异,正源于它们在这场“事件旅行”中的不同角色。


1. event.target:事件的“起点”


定义​:触发事件的最深层元素,即用户实际交互的对象。


特点​:



  • 从事件触发到结束,始终指向最初的“罪魁祸首”(即使事件冒泡到父元素,它也不会变)。
  • 可能是按钮、文本节点,甚至是动态生成的元素。

示例​:点击一个嵌套的 <div>内部的 <span>event.target始终是 <span>


2. event.currentTarget:事件的“处理者”


定义​:当前正在执行事件处理程序的元素,即绑定事件监听器的那个元素。


特点​:



  • 随着事件在捕获/冒泡阶段流动,它的值会动态变化(从外层元素逐渐向内,或从内层向外)。
  • 在非箭头函数的回调中,this等价于 event.currentTarget

示例​:父元素绑定点击事件,子元素被点击时,父元素的回调函数中 event.currentTarget是父元素,而 event.target是子元素。


二、一张图看懂:事件流中的身份切换


为了更直观理解二者的差异,我们通过一个三层嵌套结构的交互演示:


<div id="outer" class="box">外层(绑定事件)
<div id="middle" class="box">中层
<div id="inner" class="box">内层(点击我)</div>
</div>
</div>

当点击最内层的 inner元素时,事件流的三个阶段中,currentTarget和 target的变化如下:


阶段event.currentTarget(处理者)event.target(触发者)
捕获阶段outer → middle → innerinner(始终不变)
目标阶段innerinner
冒泡阶段inner → middle → outerinner(始终不变)

关键结论​:



  • target是“事件的源头”,永远指向用户点击的那个元素。
  • currentTarget是“事件的搬运工”,随事件传播阶段变化,指向当前处理事件的元素。

三、为什么需要事件委托?用差异解决实际问题


传统事件绑定方式为每个子元素单独添加监听器,但在动态列表、表格等场景下,这会导致 ​内存浪费动态元素难维护代码冗余​ 三大痛点。而事件委托的出现,正是利用 currentTarget和 target的差异,提供了一种“集中管理、按需处理”的优化方案。


事件委托的核心逻辑


原理​:将子元素的事件监听绑定在父元素上,利用事件冒泡机制,由父元素统一处理子元素的事件。


关键依赖​:



  • 父元素(currentTarget)负责接收事件。
  • 通过 event.target识别实际触发的子元素,执行针对性逻辑。

经典场景实战


场景 1:动态待办列表的点击交互


需求:点击待办项标记完成,支持动态添加新任务。


传统方式的问题​:每次新增任务都要重新绑定事件,代码冗余且易出错。


事件委托方案​:


<ul id="todoList">
<li class="todo-item">任务 1(点击标记完成)</li>
<li class="todo-item">任务 2(点击标记完成)</li>
</ul>
<button id="addTodo">添加新任务</button>

const todoList = document.getElementById('todoList');
const addTodoBtn = document.getElementById('addTodo');

// 父元素 todoList 绑定唯一点击事件(冒泡阶段)
todoList.addEventListener('click', function(event) {
// event.target 是实际点击的元素(可能是 li 或其子元素)
const target = event.target.closest('.todo-item'); // 向上查找最近的 li

if (!target) return; // 非目标元素,跳过

// 标记完成(切换类名)
target.classList.toggle('completed');

// 若点击删除按钮(假设子元素有 .delete-btn)
if (target.querySelector('.delete-btn')) {
target.remove(); // 直接删除父元素 li
}
});

// 动态添加新任务(无需重新绑定事件)
addTodoBtn.addEventListener('click', () => {
const newTodo = document.createElement('li');
newTodo.className = 'todo-item';
newTodo.innerHTML = `新任务 ${Date.now()} <button class="delete-btn">删除</button>`;
todoList.appendChild(newTodo);
});

优势​:



  • 仅需绑定一次父元素事件,内存占用极低。
  • 新增任务自动继承事件处理能力,无需额外代码。

场景 2:表格单元格的双击编辑


需求:双击表格单元格(td)转换为输入框编辑。


事件委托方案​:


<table id="dataTable">
<thead><tr><th>ID</th><th>名称</th></tr></thead>
<tbody>
<tr><td>1</td><td>苹果</td></tr>
<tr><td>2</td><td>香蕉</td></tr>
</tbody>
</table>

const dataTable = document.getElementById('dataTable');

// 父元素 tbody 监听双击事件(冒泡到 tbody)
dataTable.addEventListener('dblclick', function(event) {
// event.target 是实际双击的元素(可能是文本或 td)
const td = event.target.closest('td');
if (!td) return;

// 转换为输入框编辑
const originalText = td.textContent;
td.innerHTML = `<input type="text" value="${originalText}" class="edit-input">`;

const input = td.querySelector('.edit-input');
input.focus();

// 输入完成后保存(监听输入框失焦)
input.addEventListener('blur', () => {
td.textContent = input.value;
});
});

优势​:



  • 无论表格有多少行,只需绑定一次 tbody事件。
  • 新增行(如 AJAX 加载数据后插入)自动支持编辑功能。

四、避坑指南:事件委托的注意事项



  1. 选择合适的父元素

    父元素应尽可能靠近目标子元素(如列表用 ul而非 body),避免不必要的事件判断逻辑,减少性能损耗。


  2. 精确过滤目标元素

    使用 event.target.closest(selector)或 event.target.matches(selector)确保只处理目标子元素。例如:


    if (event.target.matches('.todo-item')) { ... }


    const target = event.target.closest('.todo-item'); if (target) { ... }


  3. 处理事件冒泡的中断

    若子元素调用了 event.stopPropagation(),事件不会冒泡到父元素,委托会失效。需避免在关键子元素中阻止冒泡,或改用捕获阶段监听(addEventListener第三个参数为 true)。


  4. 性能优化的边界

    对于极少量子元素(如 5 个以内),直接绑定可能更简单;但对于动态或大量子元素,事件委托是更优选择。



五、总结:从“混淆”到“精通”的关键


event.currentTarget和 event.target的核心差异,本质是 ​​“处理者”与“触发者”​​ 的分工:



  • target是用户交互的起点,始终指向实际触发的元素。
  • currentTarget是事件处理程序的载体,随事件传播阶段变化。

而事件委托,正是利用这一差异,通过父元素(currentTarget)集中处理子元素事件,解决了动态内容、批量操作的维护难题。


掌握这对属性和事件委托模式,不仅能写出更高效的代码,更能让你在前端交互设计中游刃有余。下次遇到大量子元素的事件绑定需求时,不妨试试事件委托——它会是你最可靠的“效率工具”。


作者:若尘的技术之旅
来源:juejin.cn/post/7553245651939131427

0 个评论

要回复文章请先登录注册