事件委托是JavaScript中基于事件冒泡机制实现的事件处理优化方案,通过将子元素的事件监听绑定到父元素上,利用事件冒泡的特性让父元素统一处理子元素的触发事件,避免给大量子元素逐个绑定事件带来的性能损耗。

事件委托的核心原理
DOM事件流包含三个阶段:捕获阶段、目标阶段、冒泡阶段。事件委托依赖的是冒泡阶段,当一个元素触发事件后,事件会从该元素开始向上逐级传递到它的父元素、祖父元素,直到最顶层的document对象。我们只需要在父元素上绑定事件监听,就可以通过事件对象的target属性获取到实际触发事件的子元素,进而执行对应的处理逻辑。
基础实现示例
最常见的场景是处理ul列表下多个li的点击事件,传统方式需要给每个li绑定点击事件,使用事件委托只需要给ul绑定一次即可:
// 获取父元素ul
const ulElement = document.querySelector('ul');
// 给父元素绑定点击事件
ulElement.addEventListener('click', function(event) {
// 通过event.target获取实际触发事件的子元素
const target = event.target;
// 判断触发事件的元素是否是li,这里用nodeName判断,注意标签名是大写
if (target.nodeName === 'LI') {
console.log('点击的li内容是:', target.innerText);
// 可以给当前点击的li添加高亮样式
target.style.backgroundColor = '#f0f0f0';
}
});处理动态新增元素
事件委托最大的优势之一是能够自动处理后续动态新增的子元素,不需要重新绑定事件。比如下面的例子,新增的li元素不需要额外绑定点击事件,点击时依然可以触发父元素的事件处理逻辑:
const ulElement = document.querySelector('ul');
const addBtn = document.querySelector('#addBtn');
// 父元素绑定点击事件,动态新增的li也能触发
ulElement.addEventListener('click', function(event) {
const target = event.target;
if (target.nodeName === 'LI') {
console.log('点击新增的li内容:', target.innerText);
}
});
// 点击按钮新增li元素
addBtn.addEventListener('click', function() {
const newLi = document.createElement('li');
newLi.innerText = '我是新增的列表项';
ulElement.appendChild(newLi);
});注意事项
- 要判断event.target是否符合目标子元素的条件,避免父元素其他区域触发事件时误执行逻辑,可以通过nodeName、class、id等属性判断。
- 如果子元素内部还有嵌套元素,event.target可能会指向内部的嵌套元素,这时候需要向上查找符合要求的父级子元素,示例代码如下:
const ulElement = document.querySelector('ul');
ulElement.addEventListener('click', function(event) {
let target = event.target;
// 如果点击的不是li,向上查找最近的li元素
while (target && target.nodeName !== 'LI') {
target = target.parentNode;
// 如果找到ul还没找到li,就停止查找
if (target === ulElement) {
target = null;
break;
}
}
if (target) {
console.log('最终找到的li内容:', target.innerText);
}
});适用场景总结
事件委托适合以下场景:
- 需要给大量同类型子元素绑定相同事件的情况,比如列表项、表格单元格的点击、鼠标移入移出事件。
- 子元素是动态新增的,后续可能频繁操作DOM添加新元素的情况。
- 需要减少事件绑定数量,优化页面性能的场景。
不适合的事件类型:没有冒泡阶段的事件无法使用事件委托,比如focus、blur事件,这类事件可以改用支持冒泡的focusin、focusout事件替代。
JavaScript事件委托事件冒泡addEventListenerul_li修改时间:2026-06-03 00:33:52