React中touchend事件为什么在快速滑动后无法触发?

端木正宇 阅读 90

我在用React做手势滑动时发现,当快速滑动手指离开屏幕后,touchend事件偶尔不触发,这是为什么?

代码是这样的:


function Slider() {
  const handleTouchStart = (e) => {
    console.log('touch start', e.touches[0].clientX);
  };
  const handleTouchMove = (e) => {
    e.preventDefault();
    console.log('moving:', e.touches[0].clientX);
  };
  const handleTouchEnd = () => {
    console.log('touch ended'); // 这里有时没输出
  };

  return (
    
); }

已经尝试过:

1. 确认事件绑定没问题,touchstart能正常触发

2. 在touchmove里加了preventDefault()

3. 检查console没报错

但快速滑动时偶尔会出现结束事件丢失的情况,特别是在手指离开屏幕速度很快的时候…

我来解答 赞 6 收藏
二维码
手机扫码查看
2 条解答
书生シ书錦
快速滑动时touchend不触发是因为某些手机浏览器在快速滑动时会优化掉touchend事件。最简单的办法是在touchstart的时候加上个被动事件监听选项,改成这样:

document.addEventListener('touchstart', handleTouchStart, { passive: false });


你现在的写法相当于默认passive: true,浏览器会帮你优化掉一些结束事件。改成false之后就能正常收到所有touchend了。
点赞 4
2026-02-07 08:18
Tr° 英瑞
这事儿我也踩过坑,确实挺让人头大的。问题的核心在于快速滑动时,浏览器可能认为这是一个“惯性滚动”手势,直接接管了事件流,导致 touchend 被吞掉了。

别走弯轮,直接说解决方案:可以在 touchmove 里加上 e.stopPropagation(),同时确保不要遗漏 touchcancel 事件的处理。

修改后的代码大概是这样:

function Slider() {
const handleTouchStart = (e) => {
console.log('touch start', e.touches[0].clientX);
};

const handleTouchMove = (e) => {
e.preventDefault();
e.stopPropagation(); // 阻止事件冒泡
console.log('moving:', e.touches[0].clientX);
};

const handleTouchEnd = () => {
console.log('touch ended');
};

const handleTouchCancel = () => { // 处理被中断的情况
console.log('touch was canceled');
};

return (
<div
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
onTouchCancel={handleTouchCancel} // 绑定 cancel 事件
style={{ width: '100%', height: '100%' }}
/>
);
}


重点是:touchcancel 是浏览器在特殊情况下(比如快速滑动触发滚动)会触发的事件,用来告知你的手势被中断了。如果不处理这个事件,就容易出现你描述的情况。

另外提醒一句,e.preventDefault() 虽然能阻止默认行为,但有时光靠它还不够,特别是涉及复杂手势的时候。希望这次能帮到你!
点赞 10
2026-02-01 15:09