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

react-beautiful-dnd抽屉内同Droppable拖拽时source与destination不一致问题

react-beautiful-dnd 抽屉内拖拽时source与destination不一致的问题解决

可能原因

  1. Portal 导致的 DOM 层级问题:多数抽屉组件(比如 Ant Design 的 Drawer)会使用 Portal 将内容挂载到 body 下,脱离了原本 DragDropContext 包裹的 DOM 结构。react-beautiful-dnd 依赖 DOM 位置判断拖拽目标,这种情况下容易误识别到外部的 main-droppable,导致 source 和 destination 的 droppableId 不一致。
  2. 同类型 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 06:32:45