React中touchend事件在移动端为什么没触发?
我在用React写移动端滑动删除功能时遇到问题,给元素绑定了touchstart和touchend事件,但结束触摸时事件没反应。手指离开屏幕后控制台只打印了touchstart,touchend完全没触发。
代码是这样写的:
import { useRef } from 'react';
function SwipeItem() {
const itemRef = useRef(null);
const handleTouchStart = (e) => {
console.log('touchstart触发了');
};
const handleTouchEnd = () => {
console.log('touchend为什么没触发?');
};
return (
<div
ref={itemRef}
onTouchStart={handleTouchStart}
onTouchEnd={handleTouchEnd}
style={{ height: '100px', backgroundColor: 'lightgray' }}
>
可滑动项
</div>
);
}
已经试过在touchstart里加e.preventDefault(),但页面会出现无法滚动的问题。当手指快速滑动离开元素时事件更不靠谱,这是怎么回事?
建议监听整个document的touchend,这样能确保手指离开屏幕时一定能捕获到。另外别忘了在组件卸载时清除事件监听,不然可能会导致内存泄漏。
下面是改好的代码:
这样写有几个好处:
- 不用担心手指滑出去事件丢失
- 避免阻止默认事件导致页面不能滚动
- 自动清理事件监听器
我之前也被这个坑过好几次,后来就养成习惯了,移动端touch事件直接监听document最保险。
onTouchEnd不触发通常是因为touchend的触发条件没有满足。移动设备上,touchend是在所有触点都离开屏幕时触发的,但如果你在touchstart里没有正确处理默认行为,浏览器可能会直接放弃后续事件。### 根本原因
touchend没有触发通常是因为:1. 手指快速滑动后离开屏幕时,浏览器认为这是一个滚动操作,不是完整的 touch 流程。
2. 如果你在
touchstart中调用了e.preventDefault(),但没有在touchmove中持续处理,会导致浏览器中断 touch 流程。### 解决方案
推荐的做法是添加一个
onTouchMove事件处理,用来「维持」触摸流程,并确保浏览器不会中断后续的touchend。这是修改后的完整代码:
### 注意事项
-
onTouchMove中的e.preventDefault()是关键,但要注意只在你真正需要拦截滚动的时候调用,否则可能会影响页面滚动。- 推荐用
e.touches或e.changedTouches来记录触摸点变化,用于判断滑动方向或距离。- 实际开发中推荐使用一些封装好的库(如
react-swipeable),它们已经处理了这些兼容性问题。希望这能帮你把
touchend拯救回来。React 的事件系统虽然方便,但有些底层细节还是要自己兜底 😅