You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中如何正确使用touchmove?移动端拖拽滑块失效问题

移动端拖拽滑块touchmove无效问题修复

核心问题分析

  1. touchmove事件绑定错误:在handleTouchStart中,你直接调用了handleTouchMove(e, offsetX, cursorXPoss),这会立即执行该函数并将返回值(undefined)绑定给touchmove事件,而非绑定函数本身。
  2. 拖拽距离计算逻辑错误:当前handleTouchMove里的offsetX - cursorXPoss是固定值,没有根据触摸移动的实时位置更新滑块偏移量。
  3. 未清理事件监听:添加的touchmove和touchend事件在touchend后没有移除,可能导致重复绑定或内存泄漏。

修复后的代码示例

import { useState, useEffect, useCallback, useRef } from 'react';

// 状态定义
const [isPressedDown, setIsPressedDown] = useState(false);
const [touchMoveDistance, setTouchMoveDistance] = useState(0);
const navContainerRef = useRef(null);
const navTrackRef = useRef(null);
// 存储初始触摸位置和滑块初始偏移量的ref
const touchStartData = useRef({
  initialCursorPos: 0,
  initialTrackLeft: 0
});

// 事件处理函数用useCallback包裹,确保引用稳定
const handleTouchStart = useCallback((e) => {
  setIsPressedDown(true);
  const rect = e.target.getBoundingClientRect();
  const touchX = e.touches[0].clientX - window.pageXOffset;
  const trackRect = navTrackRef.current.getBoundingClientRect();
  // 记录初始触摸位置相对于滑块的偏移,以及滑块当前的left值
  touchStartData.current = {
    initialCursorPos: touchX - trackRect.left,
    initialTrackLeft: trackRect.left
  };

  // 正确绑定事件:传递函数引用,而非立即执行
  navContainerRef.current.addEventListener('touchmove', handleTouchMove);
  navContainerRef.current.addEventListener('touchend', handleTouchEnd);
}, []);

const handleTouchMove = useCallback((e) => {
  e.preventDefault();
  if (!isPressedDown) return;
  
  const touchX = e.touches[0].clientX - window.pageXOffset;
  // 根据实时触摸位置计算滑块应该移动的距离
  const newTrackLeft = touchX - touchStartData.current.initialCursorPos;
  setTouchMoveDistance(newTrackLeft - touchStartData.current.initialTrackLeft);
}, [isPressedDown]);

const handleTouchEnd = useCallback(() => {
  setIsPressedDown(false);
  // 移除事件监听,避免重复绑定
  navContainerRef.current.removeEventListener('touchmove', handleTouchMove);
  navContainerRef.current.removeEventListener('touchend', handleTouchEnd);
}, []);

// 初始化touchstart事件监听
useEffect(() => {
  const container = navContainerRef.current;
  container.addEventListener('touchstart', handleTouchStart);
  
  // 组件卸载时清理初始事件
  return () => {
    container.removeEventListener('touchstart', handleTouchStart);
  };
}, [handleTouchStart]);

// 滑块渲染部分
<div
  style={{
    left: `${isPressedDown ? touchMoveDistance : mouseHoverEvent}px`,
  }}
  className={styles.navTrack}
  ref={navTrackRef}
>
  {/* 子元素内容保持不变 */}
</div>

关键修改点说明

  • 事件绑定方式:将handleTouchMove(e, offsetX, cursorXPoss)改为直接传handleTouchMove,确保事件触发时调用正确的函数。
  • 实时位置计算:通过touchStartData存储初始触摸位置和滑块初始偏移,在touchmove时根据当前触摸位置计算实时偏移量。
  • 事件清理:在touchend和组件卸载时移除对应的事件监听,避免内存泄漏。
  • useCallback优化:用useCallback包裹事件处理函数,确保函数引用稳定,避免不必要的重绑定。

内容的提问来源于stack exchange,提问作者Oliver

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 08:10:46