基础概念
DndContext用于包装拖拽根组件,Draggable和Droppable都需要包裹在DndContext内Droppable用于包装接收拖拽元素的组件,使组件能够放置Draggable用于包装需要拖动的组件,使组件能够被拖拽SortableContext创建一个拖放排序的容器,其中的子元素可以被拖动并重新排序Sensors用于检测不同的输入方法,以启动拖动操作、响应移动以及结束或取消操作,内置传感器:指针、鼠标、触摸、键盘
安装依赖
@dnd-kit/core: 6.0.8, @dnd-kit/sortable: 7.0.2, @dnd-kit/utilities: 3.2.1,
useSensors是@dnd-kit库中的一个函数,用于配置和管理拖拽操作的传感器。传感器是用于检测用户交互的输入设备或方式的模块。useSensor(PointerSensor)行创建了一个名为PointerSensor的传感器实例,并将其添加到sensors数组中。PointerSensor用于捕获指针设备(如鼠标或触摸屏)的交互,允许用户通过拖拽来操作元素。useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })行创建了一个名为KeyboardSensor的传感器实例,并将其添加到sensors数组中。这里还提供了一个选项对象,指定了coordinateGetter函数,用于确定键盘输入的坐标。KeyboardSensor允许用户使用键盘来操作元素,通常用于键盘控制的排序。
            
            
              js
              
              
            
          
          import React, { FC, useState } from "react";
import {
  DndContext,
  closestCenter,
  KeyboardSensor,
  PointerSensor,
  useSensor,
  useSensors,
  DragEndEvent,
} from "@dnd-kit/core";
import {
  arrayMove,
  SortableContext,
  sortableKeyboardCoordinates,
  verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import Item from "./Item";
type ComponentType = {
  fe_id: string;
  title: string;
};
const Container: FC = () => {
  const [items, setItems] = useState<ComponentType[]>([
    { fe_id: "c1", title: "组件1" },
    { fe_id: "c2", title: "组件2" },
    { fe_id: "c3", title: "组件3" },
  ]);
  // 配置和管理拖拽操作的传感器
  const sensors = useSensors(
    useSensor(PointerSensor),
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates,
    })
  );
  const itemsWithId = items.map((c) => {
    return {
      ...c,
      id: c.fe_id,
    };
  });
  return (
    <DndContext
      sensors={sensors}
      collisionDetection={closestCenter}
    >
      <SortableContext
        items={itemsWithId}
        strategy={verticalListSortingStrategy}
      >
        {itemsWithId.map((c) => (
          <Item key={c.id} id={c.id} title={c.title} />
        ))}
      </SortableContext>
    </DndContext>
  );
};
export default Container;
        设置 onDragEnd 函数。
- 从 
event对象中解构出active和over属性。active代表拖动操作的起点元素,over代表拖动操作的结束点元素。 - 检查起点元素和结束点元素的 
id是否不相同。 - 使用 
arrayMove函数将active元素从oldIndex移动到newIndex,实现元素的重新排序。 
            
            
              js
              
              
            
          
          function handleDragEnd(event: DragEndEvent) {
  const { active, over } = event;
  if (over == null) return;
  if (active.id !== over.id) {
    setItems((items) => {
      const oldIndex = items.findIndex((c) => c.fe_id === active.id);
      const newIndex = items.findIndex((c) => c.fe_id === over.id);
      return arrayMove(items, oldIndex, newIndex);
    });
  }
}
        Item.tsx
attributes: 这是一个包含属性的对象,通常应用于拖拽目标元素,以便处理拖拽的交互。这些属性包括样式属性、拖拽相关的属性等,用于实现拖拽时的视觉效果。listeners: 这是一个包含事件监听器的对象,用于监听拖拽过程中的事件,例如拖拽开始、拖拽结束等。这些事件监听器应该绑定到拖拽目标元素,以便捕获用户的拖拽操作。setNodeRef: 这是一个回调函数,用于设置拖拽目标元素的引用。通常,你需要将这个回调函数传递给要进行拖拽的元素,以确保能够正确地识别和操作拖拽目标。transform: 这是一个用于处理拖拽元素的变换效果的 CSS 属性。可以使用它来应用平移(translation)、缩放(scale)等变换,以使拖拽效果看起来更加自然。transition: 这是一个用于定义拖拽元素的过渡效果的 CSS 属性。可以使用它来创建平滑的过渡动画,使拖拽操作更加流畅。
            
            
              js
              
              
            
          
          import React, { FC } from "react";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
type PropsType = {
  id: string;
  title: string;
};
const Item: FC<PropsType> = (props: PropsType) => {
  const { id, title } = props;
  const { attributes, listeners, setNodeRef, transform, transition } =
    useSortable({ id });
  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
    border: "1px solid #ccc",
    margin: "10px 0",
    background: "#f1f1f1",
  };
  return (
    <div ref={setNodeRef} style={style} {...attributes} {...listeners}>
      Item {title}
    </div>
  );
};
export default Item;
        