参考文档 组件源码

import React from 'react';
import {
  DndContext, // DndKit的核心组件,用于处理拖拽和排序的上下文
  closestCenter, // 用于检测最接近的位置
  KeyboardSensor, // 用于处理键盘拖拽
  useSensor, // 自定义Hook,用于使用传感器
  useSensors, // 自定义Hook,用于使用多个传感器
  MouseSensor, // 用于处理鼠标拖拽
} from '@dnd-kit/core';
import {
  arrayMove, // 用于移动数组中的元素位置
  SortableContext, // 用于创建可排序的上下文
  sortableKeyboardCoordinates, // 用于处理可排序元素的键盘坐标
  useSortable, // 自定义Hook,用于实现可排序元素的行为
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
 
// SortListDndKit组件
const SortListDndKit = ({
  list = [],
  idKey = 'id',
  children,
  onDragEnd,
}) => {
  // 使用多个传感器
  const sensors = useSensors(
    useSensor(MouseSensor), // 使用鼠标传感器
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates, // 使用键盘传感器,并指定键盘坐标的获取方式
    }),
  );
 
  // 拖拽结束的处理函数
  const handleDragEnd = (event) => {
    const { active, over } = event; // 获取拖拽事件对象中的active和over属性
    if (active.id !== over.id) { // 如果拖拽的元素和目标元素不是同一个
      const oldIndex = list.findIndex((item) => item[idKey] === active.id); // 找到拖拽元素在列表中的索引
      const newIndex = list.findIndex((item) => item[idKey] === over.id); // 找到目标元素在列表中的索引
      const ids = list.map((item) => item[idKey]); // 获取列表中所有元素的id
      [ids[newIndex], ids[oldIndex]] = [ids[oldIndex], ids[newIndex]]; // 交换目标元素和拖拽元素的id位置
      const _val = arrayMove(list, oldIndex, newIndex); // 根据索引交换列表中元素的位置
      onDragEnd(_val, ids); // 调用传入的onDragEnd回调函数,并传递更新后的列表和id数组
    }
  };
 
  return (
    <DndContext
      sensors={sensors} // 传递传感器给DndContext
      collisionDetection={closestCenter} // 设置碰撞检测器为closestCenter
      onDragEnd={handleDragEnd} // 设置拖拽结束的处理函数
    >
      <SortableContext items={list.map((item) => item[idKey])}>
        {children}
      </SortableContext>
    </DndContext>
  );
};
 
// SortItemDndKit组件
const SortItemDndKit = ({ id, children, handle = false, handleNode, ...props }) => {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id }); // 使用useSortable自定义Hook,获取可排序元素的属性和行为
 
  const style = {
    transform: CSS.Transform.toString(transform), // 将transform属性转换为字符串
    transition,
    ...(isDragging ? { boxShadow: '0 4px 8px rgba(0, 0, 0, 0.2)', zIndex: 1000, position: 'relative' } : {}),
  };
 
  const newChild = React.Children.map(children, (child) => {
    if (!React.isValidElement(child)) {
      return null;
    }
    const childProps = {
      ...child.props,
      ref: setNodeRef, // 将元素的引用设置为setNodeRef
      ...(handle ? {} : attributes),
      ...(handle ? {} : listeners),
    };
    return React.cloneElement(child, childProps); // 克隆子元素,并传递属性和事件监听器
  });
 
  if (handle) {
    return <div {...props} style={{ ...style }}>
      <div className='handleNode' {...listeners} style={{ cursor: 'pointer' }} >{handleNode || '+'}</div>
      <div>{newChild}</div>
    </div >
  }
  if (!handle) {
    return <div style={{ ...style, cursor: 'pointer' }}>
      {newChild}
    </div>
  }
};
 
 
export { SortListDndKit, SortItemDndKit };
 
 
 
// 使用方法:
// 1. 导入SortListDndKit和SortItemDndKit组件。
// 2. 在需要拖拽和排序的列表的父组件中使用SortListDndKit组件作为容器组件。
// 3. 在SortListDndKit组件内部,将列表数据传递给list属性,列表项的唯一标识符传递给idKey属性,以及在拖拽结束时触发的回调函数传递给onDragEnd属性。
// 4. 使用SortItemDndKit组件作为列表项的包装组件,并将每个列表项的唯一标识符传递给id属性。
// 5. 在SortItemDndKit组件内部,将要排序的内容作为子元素传递。
// 6. 在onDragEnd回调函数中,可以获取排序后的列表数据和id数组,并进行进一步的处理。
 

使用方法

import React, { useState } from 'react'
import InnerTopBar from "@/components/Layouts/InnerTopBar";
import { Button } from "antd";
import { SortListDndKit, SortItemDndKit } from './Sortable';
 
export default function RroupedSorting() {
  const [list, setList] = useState([
    { id: "1", text: "Item 1" },
    { id: "2", text: "Item 2" },
    { id: "3", text: "Item 3" }
  ]);
 
  const handleDragEnd = (sortedList, sortedIds) => {
    console.log("Sorted List:", sortedList);
    console.log("Sorted Ids:", sortedIds);
 
    // 更新列表数据为排序后的顺序
    setList(sortedList);
  };
  return (
    <div>
 
      <InnerTopBar
        leftTitle="返回"
        returnPath="/flow/flowForm"
        rightTool={[<Button>保存</Button>]}
      />
 
      <SortListDndKit list={list} onDragEnd={handleDragEnd}>
        {list.map((item) => (
          <SortItemDndKit
            key={item.id}
            id={item.id}
            handle={true}
            handleNode={'🤚'}
            className='SortItemDndKit'
          >
            <div>{item.text}</div>
          </SortItemDndKit>
        ))}
      </SortListDndKit>
 
    </div>
  )
}