原生JS实现父元素事件委托:点击<li>时排除子元素且兼容IE11
问题背景
你提到的场景非常典型——用jQuery的事件委托轻松处理动态生成的.item元素,现在要转成纯原生JS,还得兼容IE11、不能用closest(),同时要确保点击逻辑只关联到<li>元素(不管点击的是它本身还是子元素),还要避开逐个绑定事件带来的性能和动态元素失效问题。
解决方案思路
核心逻辑和jQuery事件委托完全一致:把点击事件绑定到更上层的父元素(推荐用#list-items而非document,性能更优),借助事件冒泡的特性,从触发点击的元素开始向上遍历,找到对应的.item元素(手动实现closest()的替代逻辑,适配IE11),再执行后续业务代码。
具体实现代码
首先写一个兼容IE11的closest()替代函数,用来从目标元素向上查找匹配选择器的祖先:
function getClosest(el, selector) { // 从当前元素开始向上遍历,直到找到匹配元素或到达document while (el && el !== document) { // 兼容IE11的matchesSelector前缀 const matchesFn = el.matches || el.msMatchesSelector; if (matchesFn && matchesFn.call(el, selector)) { return el; } el = el.parentNode; } return null; }
然后绑定事件委托:
// 绑定到离目标元素最近的父容器,减少冒泡层级提升性能 document.getElementById('list-items').addEventListener('click', function(e) { // 从点击的元素向上找到对应的.item const targetItem = getClosest(e.target, '.item'); // 确认找到目标元素后再执行逻辑 if (targetItem) { // 获取data属性,两种方式都兼容IE11 const id = targetItem.getAttribute('data-id'); // 更稳妥的兼容写法 const title = targetItem.dataset.title; // IE11支持dataset,连字符属性会转成驼峰 // 这里写入你的业务逻辑 console.log('当前点击项ID:', id, '标题:', title); } });
关键细节说明
为什么不直接判断
e.target是.item?
点击<li>内部的<img>、<a>等子元素时,e.target会是这些子元素,而不是<li>本身。向上遍历的逻辑和jQuery事件委托的行为对齐——只要点击的是.item或它的子元素,都会触发对应逻辑。关于data属性的读取
IE11支持dataset,但对于data-my-title这类带连字符的属性,需要写成dataset.myTitle;如果怕记错驼峰规则,直接用getAttribute('data-id')是更通用的兼容写法。动态元素的支持
因为事件绑定在父容器上,后续动态添加的.item元素不需要额外绑定事件,父容器会自动捕获它们的点击事件,和jQuery的表现完全一致。性能优化
绑定到#list-items而非document,能减少事件冒泡的层级,避免不必要的事件触发,页面元素较多时性能差异会更明显。
内容的提问来源于stack exchange,提问作者Siddharth Thevaril

