事件委托怎么拿不到动态添加的子元素数据?

A. 俊焱 阅读 20

我用事件委托给一个 ul 绑定了点击事件,想通过 e.target 获取 li 里的 data-id,但新 append 进去的 li 点击后拿不到属性,老的却可以。是不是我写法有问题?

我试过把事件监听器加在 document 上也不行,代码大概是这样:

document.querySelector('ul').addEventListener('click', function(e) {
  if (e.target.tagName === 'LI') {
    console.log(e.target.dataset.id);
  }
});
我来解答 赞 6 收藏
二维码
手机扫码查看
2 条解答
UX-长春
UX-长春 Lv1
问题出在你判断的是 e.target.tagName === 'LI',但点击事件可能发生在 li 的子元素上(比如里面的 span 或文本节点)。直接用这个:

document.querySelector('ul').addEventListener('click', function(e) {
const li = e.target.closest('li');
if (li) {
console.log(li.dataset.id);
}
});


closest() 方法会往上找最近的 li 元素,不管你是点到 li 本身还是里面的子元素都能正确获取。比直接判断 tagName 靠谱多了,我调试动态元素经常用这招。
点赞 1
2026-03-09 21:06
小庆玲
小庆玲 Lv1
这个坑我之前也踩过,问题不在事件委托本身,而是 e.target 指向的是你点击的最内层元素。

如果你的 li 里面有其他元素,比如 span 或者文字节点,点击的时候 e.target 就会是那个 span,而不是 li。所以你的 tagName === 'LI' 判断直接就挂了,根本走不到 log 那一行。

老的 li 能拿到数据,估计是因为里面没有子元素,点击直接命中 li 本身。

解决方法很简单,用 closest() 往上找:

document.querySelector('ul').addEventListener('click', function(e) {
const li = e.target.closest('li');
if (li) {
console.log(li.dataset.id);
}
});


这样不管你点的是 li 本身还是它里面的 span、div、图标什么的,都能正确找到对应的 li 元素。

另外还有个细节要注意,closest() 会从当前元素开始往上找,包括元素自己,所以不用再额外判断 tagName 了。如果点击的是 ul 外面的区域,closest('li') 会返回 null,加个判断就行。

这个方法对动态添加的元素完全没问题,事件委托本来就是干这个事的。
点赞 2
2026-03-01 10:07