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;