事件委托是利用事件冒泡机制,在父元素上统一监听子元素事件,通过event.target和closest()精准识别目标节点,实现一次绑定、动态生效、高效维护。

直接在父元素上监听点击事件,利用事件冒泡 + event.target 判断真实点击目标,就能统一管理所有当前和未来新增的子元素——不用给每个子元素单独绑事件,也不用为动态插入的元素重复绑定。
选对父容器,别跨层级委托
委托应尽量靠近子元素,比如列表用 <ul></ul>,表格用 <table> 或 <code><tbody>。离得太远(如直接绑到 <code>document)虽能工作,但冒泡路径变长、响应延迟增加,还容易被中间层的 stopPropagation() 拦截。
- ✅ 推荐:绑定到直接父级(如
ul管理所有li) - ❌ 避免:绑定到
body或document处理按钮点击(除非全局行为)
用 event.target 精准识别触发元素
点击发生后,event.target 指向**最底层被点击的 DOM 节点**(可能是子元素,也可能是子元素里的 span 或 img)。所以不能只看标签名,要向上查找匹配的“业务目标”。
- 用
event.target.closest('selector')安全获取目标子元素(自动向上找最近匹配项) - 避免直接写
if (e.target.tagName === 'LI')—— 如果用户点的是li里的文字或图标,e.target就是那个textNode或span,条件会失败
代码写法要兼顾静态与动态场景
只要父元素存在且事件监听器已绑定,后续用 JS 插入的新子元素(例如 ul.appendChild(newLi))无需额外操作,点击即生效。
- 监听器只需绑定一次,通常放在初始化或父容器渲染完成后
- 处理逻辑中用
closest()获取业务单元,再读取其数据属性(如data-id)或结构信息 - 示例:
const list = document.getElementById('item-list');
list.addEventListener('click', e => {
const item = e.target.closest('li');
if (!item) return;
console.log('操作第', item.dataset.id);
});
注意边界与兼容性细节
事件委托不是万能的,有些情况需额外判断:
- 确保子元素本身没调用
e.stopPropagation(),否则冒泡中断,父元素收不到 - 表单控件(如
input、select)的某些事件(如input、change)也支持冒泡,可委托;但focus/blur不冒泡,需另寻方案 -
closest()在 IE 中不支持,如需兼容旧浏览器,可用 polyfill 或手动遍历parentNode


















