Skip to content
字数
598 字
阅读时间
3 分钟

DndContext 组件是 @dnd-kit/core 的核心组件,它接收一个 onDragEnd 属性:

ts
  return (
    <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
      <SortableContext items={items} strategy={verticalListSortingStrategy}>
        {children}
      </SortableContext>
    </DndContext>
  )

当拖拽结束时,onDragEnd 回调会被触发,它接收一个 DragEndEvent 类型的事件对象:

ts
  function handleDragEnd(event: DragEndEvent) {
    const { active, over } = event
    if (over == null) return

    if (active.id !== over.id) {
      const oldIndex = items.findIndex(c => c.fe_id === active.id)
      const newIndex = items.findIndex(c => c.fe_id === over.id)
      onDragEnd(oldIndex, newIndex)
    }
  }

这个事件对象包含两个重要属性:

  • active: 被拖拽的元素信息(包含其id)

  • over: 放置目标的元素信息(包含其id)

  • 在回调函数中,我们通过这两个id找到它们在数组中的索引位置:

const oldIndex = items.findIndex(c => c.fe_id === active.id)

const newIndex = items.findIndex(c => c.fe_id === over.id)

  • 最后通过 Redux dispatch 一个 action 来交换这两个位置的元素:

所以整个拖拽排序的流程是:

  • 用户拖拽结束时触发 onDragEnd

  • 获取拖拽元素和目标元素的id

  • 找到这两个元素在数组中的位置

  • 交换这两个位置的元素完成排序

这就是 @dnd-kit 库实现拖拽排序的核心机制。

onDragEnd自动向handleDragEnd传入的event吗 是的。在 DndContext 组件中,当拖拽结束时会自动调用 onDragEnd 属性指定的回调函数,并传入一个 DragEndEvent 类型的事件对象。

这里的 event 参数是由 @dnd-kit/core 库自动传入的,它包含了:

  • active: 被拖拽的元素信息

  • over: 放置目标的元素信息

这是 @dnd-kit 库的标准行为,我们不需要手动传入这个事件对象,库会在拖拽结束时自动处理这个过程。

sensors 属性是用来配置拖拽的触发条件的。在这个项目中:

const sensors = useSensors(

ts
  const sensors = useSensors(
    useSensor(MouseSensor, {
      activationConstraint: {
        distance: 8, // 8px
      },
    })
  )

这段代码配置了一个鼠标传感器(MouseSensor),设置了以下内容:

  • useSensors 和 useSensor 是 @dnd-kit/core 提供的 hooks,用于创建和组合传感器

  • MouseSensor 用于监听鼠标事件

  • activationConstraint 配置了激活条件:

  • distance: 8 表示鼠标需要移动至少 8 像素才会触发拖拽,这可以避免用户不小心触发拖拽

这个配置传递给了 DndContext:

贡献者

The avatar of contributor named as sunchengzhi sunchengzhi

文件历史

撰写