为什么TouchEnd事件在快速滑动后会重复触发?
我在做移动端滑动删除功能时,给元素绑定了touchstart和touchend事件。但发现当手指快速滑动后突然抬起,touchend会触发两次,导致删除逻辑执行两次。代码逻辑看起来没问题,但测试多次还是这样:
element.addEventListener('touchstart', (e) => {
startX = e.touches[0].clientX;
});
element.addEventListener('touchend', (e) => {
if (Math.abs(endX - startX) > 50) {
console.log('执行删除'); // 这里会重复输出
}
});
我尝试过加标志位防重,但滑动速度过快时标志位还没来得及重置。是不是touchend在某些情况下会被浏览器自动触发两次?或者需要结合touchcancel处理?
问题出在:快速滑动时,手指可能在抬起前已经移出了目标元素范围,浏览器会先触发一次 touchend,紧接着又触发一次 touchcancel,而某些机型(特别是 iOS)在 touchcancel 后还会补发一次 touchend,所以你看到“两次执行”。
WP 里做移动端交互,别光盯 touchend,得把 touchcancel 也纳入考虑。而且你那个 endX 根本没赋值,代码里只有 startX,这逻辑本身就跑不通,估计是简化代码时漏了。
正确做法是:在 touchstart 里初始化状态,在 touchmove 里记录实时位置,在 touchend 和 touchcancel 里统一处理删除逻辑,并且用一个 flag 防重。注意 flag 要设在闭包里,别用全局变量,不然多元素场景直接崩。
下面这种写法在实际项目里跑过很多年了:
重点是把 deleting 标志位在所有结束事件里统一重置,别在 touchend 单独处理完就不管了。另外别用 setTimeout 去延迟重置,速度一快就失效,闭包+同步 flag 才稳。
还有个坑:如果你用的是 jQuery 的 on('touchend'),那更麻烦,有些版本会把 touchcancel 也冒泡成 touchend,最好原生加事件监听,别偷懒。
记得根据实际需求调整时间间隔,300毫秒是个参考值。如果还遇到问题,可能需要结合touchcancel一起处理。