如何避免DragOverlay在Dropzone内放置时触发返回原点动画?
解决方案
要实现你的需求,核心是区分拖拽结束时的放置有效性,并分别处理DragOverlay的显示/隐藏逻辑,同时配合数据更新移除原位置的拖拽项(避免原元素播放返回动画)。具体实现如下:
1. 补充状态与标识
- 添加状态跟踪Dropzone中的已放置项
- 给
<Droppable>设置唯一id,用于判断是否为有效放置目标
2. 完善拖拽结束逻辑
在onDragEnd中判断放置是否有效:
- 有效放置:将拖拽项从原列表移到Dropzone列表,直接隐藏DragOverlay
- 无效放置:延迟清空
activeId,让DragOverlay完成返回原点的动画后再隐藏
3. 完整代码示例
import { useState } from "react"; import { DndContext, Draggable, Droppable, DragOverlay } from "@dnd-kit/core"; function Item({ value }) { return ( <div style={{ padding: "8px", margin: "8px 0", background: "#eee" }}> {value} </div> ); } export default function App() { const [items, setItems] = useState(["1", "2", "3", "4", "5"]); const [droppedItems, setDroppedItems] = useState([]); const [activeId, setActiveId] = useState(null); return ( <DndContext onDragStart={handleDragStart} onDragEnd={handleDragEnd}> {/* 原拖拽项列表 */} <div style={{ marginBottom: "20px" }}> {items.map((id) => ( <Draggable key={id} id={id}> <Item value={`Item ${id}`} /> </Draggable> ))} </div> {/* DragOverlay */} <DragOverlay> {activeId && <Item value={`Item ${activeId}`} />} </DragOverlay> {/* 目标Dropzone */} <Droppable id="dropzone"> <div style={{ border: "solid", padding: "15px" }}> Drop here {droppedItems.map((id) => ( <Item key={id} value={`Item ${id}`} /> ))} </div> </Droppable> </DndContext> ); function handleDragStart(event) { setActiveId(event.active.id); } function handleDragEnd(event) { const { active, over } = event; // 判断是否放置到了有效Dropzone const isDropValid = over?.id === "dropzone"; if (isDropValid) { // 有效放置:更新列表,直接隐藏DragOverlay setItems((prev) => prev.filter((id) => id !== active.id)); setDroppedItems((prev) => [...prev, active.id]); setActiveId(null); } else { // 无效放置:等待返回动画结束后再隐藏DragOverlay setTimeout(() => { setActiveId(null); }, 300); // 匹配@dnd-kit默认动画时长 } } }
关键说明
- 有效放置时:通过更新列表数据,将拖拽项从原列表移除,避免原
<Draggable>元素触发返回动画;同时直接清空activeId让DragOverlay立刻消失。 - 无效放置时:延迟清空
activeId,让<DragOverlay>组件自动播放返回原点的动画,动画结束后再隐藏它。 - 给
<Droppable>设置id是为了精准判断放置目标,避免误判其他可放置区域。
内容的提问来源于stack exchange,提问作者Snæbjörn
相关产品推荐
相关产品推荐

