react中使用dnd-kit实现拖拽排序

dnd-kit

官网

入口: https://ant-design.antgroup.com/docs/react/recommendation-cn
仓库: https://github.com/clauderic/dnd-kit
官网: https://dndkit.com/

介绍

DnD-Kit(Drag and Drop Kit)是一个用于构建可拖放用户界面的React库。
它被设计为轻量级、模块化、高性能,并且易于集成到现有的React应用程序中。
DnD-Kit的主要目标是提供一个简单而强大的API来处理拖放操作,同时保持高度的可定制性和可访问性。

主要特点

  • 轻量级:DnD-Kit仅包含实现拖放功能所必需的核心代码,这使得它的体积小且加载速度快。
  • 模块化:库被分解成多个独立的模块,可以根据需要选择性地导入所需的组件或功能。
  • 高性能:通过优化算法和利用React的特性,DnD-Kit能够高效地处理复杂的拖放场景。
  • 可访问性:DnD-Kit遵循WCAG指南并支持ARIA属性,确保拖放操作对于所有用户都是可访问的。
  • 可扩展性:开发者可以通过自定义传感器、识别器等来扩展DnD-Kit的功能,以适应特定的应用需求。

安装

npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/modifiers @dnd-kit/utilities --save
  • @dnd-kit/core:核心库,提供基本的拖拽功能。
  • @dnd-kit/sortable:扩展库,提供排序功能和工具。
  • @dnd-kit/modifiers:修饰库,提供拖拽行为的限制和修饰功能。
  • @dnd-kit/utilities:工具库,提供 CSS 和实用工具函数。

使用

最基础的上下文

需要先使用 <DndContext /> 组件包裹需要实现拖拽效果的组件,相当于可拖拽的范围容器

import React from 'react';
import {DndContext} from '@dnd-kit/core';

// 这些是实现的各种组件
import {Draggable} from './Draggable';
import {Droppable} from './Droppable';

function App() {
  return (
    <DndContext>
       // 组件包裹在内
      <Draggable />
      <Droppable />
    </DndContext>
  )
}

示例

导入必要包

import type { DragEndEvent } from "@dnd-kit/core";
import { DndContext } from "@dnd-kit/core";
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
import {
    arrayMove,
    SortableContext,
    useSortable,
    /*
    垂直列表使用verticalListSortingStrategy,
	横向列表使用horizontalListSortingStrategy
	*/
    verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { Card } from "antd";
import * as React from "react";
import { useState } from "react";

准备数据

interface ItemType {
    id: number;
    name: string;
}

const App = () => {
    const data: ItemType[] = [
        { id: 1, name: "列表项1" },
        { id: 2, name: "列表项2" },
        { id: 3, name: "列表项3" },
        { id: 4, name: "列表项4" },
    ];
    const [items, setItems] = useState(data);
    return (
        <>
            // 组件部分
            // ......
        </>
    );
};

export default App;

实现一个可拖拽组件

interface ItemType {
    id: number;
    name: string;
}

const DraggableListNode = (props: ItemType) => {
    const { attributes, listeners, setNodeRef, transform, transition } = useSortable({
        id: props.id,
    });

    const style = {
        transform: CSS.Transform.toString(transform),
        transition,
        marginTop: 8,
    };

    return (
        <Card bordered style={style} ref={setNodeRef} {...attributes} {...listeners}>
            // 这里简单展示了name
            {props.name}
        </Card>
    );
};

在组件中应用拖拽组件

const App= () => {
    // 这是拖拽结束的响应方法
    const handleDragEnd = ({ active, over }: DragEndEvent) => {
        console.log(active);
        console.log(over);
        // 当拖拽前后的id不一致时,说明完成了有效的拖拽行为
        if (active.id !== over?.id) {
            // 对数据进行修改
            const activeIndex = items.findIndex((i) => i.id === active.id);
            const overIndex = items.findIndex((i) => i.id === over?.id);
            const newlist = arrayMove(items, activeIndex, overIndex);
            setItems(newlist);
        }
    };
    return (
        <>
            <DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={handleDragEnd}>
                <SortableContext
                    items={items.map((i: ItemType) => i.id)}
                    // 设置竖向拖拽
                    strategy={verticalListSortingStrategy}
                >
                    {items.map((item: ItemType) => (
                        <DraggableListNode key={item.id} {...item} />
                    ))}
                </SortableContext>
            </DndContext>
        </>
    );
};

export default App;

完整代码

import type { DragEndEvent } from "@dnd-kit/core";
import { DndContext } from "@dnd-kit/core";
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
import {
    arrayMove,
    SortableContext,
    useSortable,
    /*
    垂直列表使用verticalListSortingStrategy,
	横向列表使用horizontalListSortingStrategy
	*/
    verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { Card } from "antd";
import * as React from "react";
import { useState } from "react";

interface ItemType {
    id: number;
    name: string;
}

const DraggableListNode = (props: ItemType) => {
    const { attributes, listeners, setNodeRef, transform, transition } = useSortable({
        id: props.id,
    });

    const style = {
        transform: CSS.Transform.toString(transform),
        transition,
        marginTop: 8,
    };

    return (
        <Card bordered style={style} ref={setNodeRef} {...attributes} {...listeners}>
            {props.name}
        </Card>
    );
};

const App= () => {
    const data: ItemType[] = [
        { id: 1, name: "列表项1" },
        { id: 2, name: "列表项2" },
        { id: 3, name: "列表项3" },
        { id: 4, name: "列表项4" },
    ];
    const [items, setItems] = useState(data);
    const handleDragEnd = ({ active, over }: DragEndEvent) => {
        console.log(active);
        console.log(over);
        if (active.id !== over?.id) {
            console.log("active", active.id);
            const activeIndex = items.findIndex((i) => i.id === active.id);
            const overIndex = items.findIndex((i) => i.id === over?.id);
            const newlist = arrayMove(items, activeIndex, overIndex);
            setItems(newlist);
        }
    };
    return (
        <>
            <DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={handleDragEnd}>
                <SortableContext
                    items={items.map((i: ItemType) => i.id)}
                    strategy={verticalListSortingStrategy}
                >
                    {items.map((item: ItemType) => (
                        <DraggableListNode key={item.id} {...item} />
                    ))}
                </SortableContext>
            </DndContext>
        </>
    );
};

export default App;
posted @   厚礼蝎  阅读(1591)  评论(0编辑  收藏  举报
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示