为什么触摸事件在事件委托时target总是父元素?

ლ统泽 阅读 40

在移动端用事件委托处理多个.item元素的touchstart事件,但发现e.target始终返回父元素div.box,而不是实际点击的子元素。我尝试过把事件绑定到父元素并用closest()方法筛选,但子元素上的点击完全没反应。

代码结构是这样的:


<div class="box">
  <div class="item">1</div>
  <div class="item">2</div>
</div>

JS部分用了:


document.querySelector('.box').addEventListener('touchstart', function(e) {
  const target = e.target.closest('.item');
  if (target) console.log('clicked:', target.textContent);
});

但点击子元素时控制台没有任何输出,直接点击父容器才会触发。是不是触摸事件的事件冒泡机制和鼠标事件不一样?

我来解答 赞 8 收藏
二维码
手机扫码查看
2 条解答
宇文春萍
常见的解决方案其实是你代码里漏了一个关键点:touchstart 事件在移动端浏览器里有个默认行为(比如滚动、缩放),而且某些情况下浏览器会为了优化性能,把事件“提前消费”掉,导致你用 closest 匹配不到实际子元素,或者干脆不触发。

但更可能的问题是——你实际点击的区域根本没被 .item 占满。比如你给 .item 加了 padding 或 margin,但没设置 box-sizing: border-box,或者 .item 的高度为 0(比如内容是空的、没高度),那 touchstart 的 e.target 就会落在父级 .box 上,而不是子元素上。

先确认下你的 CSS 有没有类似问题:

.box {
width: 100%;
}
.item {
/* 确保有实际高度和点击区域 */
height: 40px;
box-sizing: border-box;
padding: 10px;
background: #eee;
}


如果 CSS 没问题,再加个兜底逻辑:别光用 closest('.item'),先打印 e.target 看看到底是谁:

document.querySelector('.box').addEventListener('touchstart', function(e) {
console.log('e.target:', e.target);
console.log('e.currentTarget:', e.currentTarget);
const target = e.target.closest('.item');
if (target) console.log('clicked:', target.textContent);
});


如果你发现 e.target 是 .box,但点击的是 .item 里的文字,那大概率是 .item 元素本身被其他层遮挡了(比如伪元素覆盖、absolute 定位的透明层),或者用了 pointer-events: none

还有一种情况是:你用的是旧版 iOS Safari(比如 iOS 12 以前),它在 touchstart 里 closest 行为不稳定,可以改用 matches('.item') + parentElement 一层层往上找:

document.querySelector('.box').addEventListener('touchstart', function(e) {
let el = e.target;
while (el && el !== e.currentTarget) {
if (el.classList && el.classList.contains('item')) {
console.log('clicked:', el.textContent);
return;
}
el = el.parentElement;
}
});


不过现在主流基本没问题,优先检查下 DOM 结构和 CSS 渲染尺寸吧,我遇到十次有九次是 item 高度为 0 或被遮挡。
点赞 1
2026-02-27 12:06
公孙伊芃
问题在于你可能在某些样式或布局上影响了事件的触发,比如子元素的尺寸或者触摸区域。确保你的 .item 元素有实际的点击区域并且没有被其他透明层覆盖。

试试直接用 e.target 判断,而不是 closest(),像这样:

document.querySelector('.box').addEventListener('touchstart', function(e) {
if (e.target.classList.contains('item')) {
console.log('clicked:', e.target.textContent);
}
});


如果还是不行,检查一下 CSS,确保 .item 元素不是被意外的层级遮挡了,或者尝试给 .box 和 .item 加上 pointer-events: auto; 看看有没有效果。
点赞 8
2026-02-18 10:00