@dnd-kit/sortable:拖拽含链接的排序项后如何阻止链接跳转
解决@dnd-kit/sortable中拖拽链接后触发跳转的问题
核心思路
拖拽释放时浏览器会把该动作识别为链接点击,进而触发跳转。我们需要区分「正常点击链接」和「拖拽后释放」两种操作,只阻止后者的默认跳转行为。
方案一:通过拖拽状态控制链接点击行为
利用useSortable返回的isDragging状态,在链接的点击事件中判断是否处于拖拽状态,若是则阻止默认跳转:
import { useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; const SortableItem = ({ id, linkUrl }) => { const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id }); const itemStyle = { transform: CSS.Transform.toString(transform), transition, opacity: isDragging ? 0.6 : 1, }; const handleLinkClick = (e) => { // 拖拽状态下阻止链接跳转 if (isDragging) { e.preventDefault(); } }; return ( <div ref={setNodeRef} style={itemStyle} {...attributes}> <a href={linkUrl} onClick={handleLinkClick} {...listeners}> 可拖拽链接项 </a> </div> ); };
方案二:记录拖拽操作状态(更精准)
如果isDragging在释放瞬间快速切换为false,可以通过自定义状态记录拖拽行为,延迟重置确保点击事件能检测到:
import { useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; import { useState } from 'react'; const SortableItem = ({ id, linkUrl }) => { const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id }); const [justDragged, setJustDragged] = useState(false); const itemStyle = { transform: CSS.Transform.toString(transform), transition, }; // 合并拖拽监听,记录拖拽开始/结束状态 const mergedListeners = { ...listeners, onDragStart: (e) => { listeners.onDragStart(e); setJustDragged(true); }, onDragEnd: (e) => { listeners.onDragEnd(e); // 延迟100ms重置,确保点击事件触发时能捕获到状态 setTimeout(() => setJustDragged(false), 100); }, }; const handleLinkClick = (e) => { if (justDragged) { e.preventDefault(); setJustDragged(false); // 立即重置,不影响后续正常点击 } }; return ( <div ref={setNodeRef} style={itemStyle} {...attributes}> <a href={linkUrl} onClick={handleLinkClick} {...mergedListeners}> 可拖拽链接项 </a> </div> ); };
方案三:将拖拽触发区域与链接分离
如果业务允许,可以把拖拽手柄放到链接外面,让用户只能通过手柄拖拽,链接仅响应正常点击:
import { useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; const SortableItem = ({ id, linkUrl }) => { const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id }); const itemStyle = { transform: CSS.Transform.toString(transform), transition, display: 'flex', gap: '8px', alignItems: 'center', }; return ( <div ref={setNodeRef} style={itemStyle} {...attributes}> {/* 拖拽手柄 */} <button type="button" {...listeners}> ☰ </button> {/* 链接仅响应正常点击 */} <a href={linkUrl}>普通链接项</a> </div> ); };
内容的提问来源于stack exchange,提问作者user17443811
相关产品推荐
相关产品推荐

