移动端手势滑动时点击穿透怎么解决?

Dev · 玉霞 阅读 73

在做卡片左右滑动删除功能时,发现手指抬起瞬间会触发下方按钮的点击事件。试过给滑动层加pointer-events: none,但阻止了滑动操作。后来用event.stopPropagation()包裹触摸事件也没用,有没有更好的解决办法?


card.addEventListener('touchstart', (e) => {
  e.preventDefault();
  // 滑动逻辑
}, { passive: false });

现在问题是当快速滑动后松手,下方的”删除”按钮还是会偶尔被点击,有没有遗漏的关键点?

我来解答 赞 10 收藏
二维码
手机扫码查看
1 条解答
夏侯圆圆
这个问题我之前做移动端的时候也踩过坑,说白了就是滑动操作和点击事件冲突了。你试过的那几个方法确实常见,但都不够彻底。我的经验是,关键点在于区分用户的意图——到底是想滑动还是想点击。

血泪教训告诉我,最靠谱的解决办法是加一个延迟判断机制。具体做法是:在用户手指抬起时,先不立刻触发点击事件,而是用一个小延迟(比如 150 毫秒)来判断刚才的操作是不是滑动。如果是滑动,就直接阻止点击事件。

代码可以这样写:

let isSwiping = false;

card.addEventListener('touchstart', (e) => {
isSwiping = false;
});

card.addEventListener('touchmove', (e) => {
isSwiping = true;
e.preventDefault(); // 阻止默认滚动行为
}, { passive: false });

card.addEventListener('touchend', (e) => {
if (isSwiping) {
e.stopPropagation();
e.preventDefault();
// 这里处理滑动结束后的逻辑
return;
}
// 如果不是滑动,才允许点击事件继续
});


这里的重点是用 isSwiping 标志位来记录用户是否触发了滑动。如果检测到滑动,就直接拦截掉后续的点击行为。这个方案的关键是 touchmovetouchend 的配合,单独靠 stopPropagation 是不够的,因为点击穿透通常是浏览器的默认行为导致的。

还有一个小技巧,如果你发现某些设备上仍然有问题,可以在 touchend 里手动给目标元素加个临时的 pointer-events: none,然后用 setTimeout 在几百毫秒后恢复。比如:

card.addEventListener('touchend', (e) => {
if (isSwiping) {
e.target.style.pointerEvents = 'none';
setTimeout(() => {
e.target.style.pointerEvents = 'auto';
}, 150);
}
});


这种方法虽然有点粗暴,但在一些极端场景下特别管用。总之,核心思路就是通过标志位和延迟判断来区分滑动和点击,别让浏览器自己去猜用户的意图,不然它经常会猜错。
点赞 1
2026-02-18 15:00