React移动端拖拽事件失效:复用桌面函数绑定触摸事件仍无效
React移动端触摸拖拽失效的问题修复
问题根源
你直接把桌面拖拽的处理函数复用给触摸事件,但触摸事件和桌面拖拽事件的机制完全不同,核心问题有两个:
onTouchEnd触发时,ev.currentTarget不一定是手指最终离开的元素(可能手指滑动过程中已经移开原元素),导致无法正确获取放置目标- 触摸事件需要通过触摸位置定位目标元素,而不是依赖事件的
currentTarget
修正方案
1. 新增触摸状态跟踪
在原有状态基础上,添加触摸相关的状态变量:
const [dragId, setDragId] = useState(null); const [array, setArray] = useState(jobsArray); // 新增:跟踪触摸起始位置和起始元素 const [touchStartPos, setTouchStartPos] = useState({ x: 0, y: 0 }); const [touchTarget, setTouchTarget] = useState(null);
2. 编写独立的触摸事件处理函数
不能直接复用桌面拖拽的handleDrag和handleDrop,需要针对触摸事件重写逻辑:
const handleDragOver = (ev) => { ev.preventDefault() }; const handleDrag = (ev) => { setDragId(ev.currentTarget.id); }; const handleDrop = (ev) => { const foundItem = array.find(job => job.title === dragId); const dragItem = array.find(job => job.title === ev.currentTarget.id); const filteredArray = array.filter(job => foundItem.title !== job.title); const elementPosition = array.indexOf(dragItem); const newArray = [...filteredArray.slice(0, elementPosition), foundItem, ...filteredArray.slice(elementPosition)]; setArray(newArray); }; // 触摸开始:记录起始位置和元素 const handleTouchStart = (ev) => { const touch = ev.touches[0]; setTouchStartPos({ x: touch.clientX, y: touch.clientY }); setTouchTarget(ev.currentTarget); setDragId(ev.currentTarget.id); }; // 触摸移动:阻止默认滚动行为,可添加视觉反馈 const handleTouchMove = (ev) => { ev.preventDefault(); // 可选:在这里添加元素跟随触摸的视觉效果 }; // 触摸结束:通过触摸位置找到实际放置目标 const handleTouchEnd = (ev) => { if (!touchTarget) return; const touch = ev.changedTouches[0]; // 根据触摸结束的坐标找到对应的DOM元素 const dropTarget = document.elementFromPoint(touch.clientX, touch.clientY); // 验证目标是我们的可拖拽项 if (dropTarget?.classList.contains('dashboard-list')) { // 复用原有的数组重排逻辑 const foundItem = array.find(job => job.title === dragId); const dragItem = array.find(job => job.title === dropTarget.id); const filteredArray = array.filter(job => foundItem.title !== job.title); const elementPosition = array.indexOf(dragItem); const newArray = [...filteredArray.slice(0, elementPosition), foundItem, ...filteredArray.slice(elementPosition)]; setArray(newArray); } // 重置状态 setTouchTarget(null); setDragId(null); };
3. 更新元素的事件绑定
把新的触摸处理函数绑定到元素上:
<div className="dashboard-list width-100 flex-center" draggable onDragOver={handleDragOver} onDragStart={handleDrag} onDrop={handleDrop} onTouchStart={handleTouchStart} onTouchEnd={handleTouchEnd} onTouchMove={handleTouchMove} id={title} > { content } </div>
额外说明
如果需要更流畅的拖拽体验,还可以在handleTouchMove中添加元素的位置偏移,让拖拽的元素跟随手指移动,增强视觉反馈。
内容的提问来源于stack exchange,提问作者Jon Nicholson
相关产品推荐
相关产品推荐

