react-beautiful-dnd抽屉内同Droppable拖拽时source与destination不一致问题
react-beautiful-dnd 抽屉内拖拽时source与destination不一致的问题解决
可能原因
- Portal 导致的 DOM 层级问题:多数抽屉组件(比如 Ant Design 的 Drawer)会使用 Portal 将内容挂载到
body下,脱离了原本DragDropContext包裹的 DOM 结构。react-beautiful-dnd 依赖 DOM 位置判断拖拽目标,这种情况下容易误识别到外部的main-droppable,导致 source 和 destination 的 droppableId 不一致。 - 同类型 Droppable 允许跨容器拖拽:你给两个 Droppable 设置了相同的
type="common",react-beautiful-dnd 默认允许同类型的 Droppable 之间互相拖拽,当抽屉的渲染位置和外部 Droppable 存在位置计算偏差时,会触发跨容器的误识别。
修复方法
方法1:为抽屉的 Droppable 设置唯一 Type
将抽屉内的 Droppable type 设置为独有的值,限制只能在同类型容器内拖拽,避免跨容器误触发:
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd"; <DragDropContext onDragEnd={onDragEnd}> <Droppable droppableId="main-droppable" type="common"> {(provided) => ( <div {...provided.droppableProps} ref={provided.innerRef}></div> )} </Droppable> {/* Drawer Component */} <Drawer> {/* 修改type为独有的值 */} <Droppable droppableId="drawer-droppable" type="drawer-item"> {(provided) => ( <div {...provided.droppableProps} ref={provided.innerRef}> {items.map((item, index) => ( <Draggable key={item.id} draggableId={item.id} index={index}> {(provided) => ( <div {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef} > {item.content} </div> )} </Draggable> ))} </div> )} </Droppable> </Drawer> </DragDropContext>
方法2:在 onDragEnd 中添加校验逻辑
如果需要保留同类型的设置,就在拖拽结束时校验 source 和 destination 的 droppableId,仅处理同容器内的拖拽:
const onDragEnd = (result) => { // 校验:仅处理同droppableId内的拖拽 if (!result.destination || result.source.droppableId !== result.destination.droppableId) { return; } // 执行你的排序逻辑 const items = Array.from(currentItems); const [reorderedItem] = items.splice(result.source.index, 1); items.splice(result.destination.index, 0, reorderedItem); setCurrentItems(items); };
方法3:处理抽屉 Portal 的层级问题
确保抽屉在拖拽时处于最高层级,避免外部 Droppable 被误触发。可以给抽屉容器添加更高的 z-index,或者调整 Portal 的挂载目标,让抽屉内容仍处于 DragDropContext 的 DOM 范围内(部分抽屉组件支持自定义挂载节点)。
比如 Ant Design Drawer 可以通过 getContainer 指定挂载节点:
<Drawer getContainer={() => document.getElementById('drag-drop-root')}> {/* Droppable 内容 */} </Drawer>
同时将 DragDropContext 放在这个指定的容器节点内。
内容的提问来源于stack exchange,提问作者Mudassar Ali
相关产品推荐
相关产品推荐

