React 拖拽排序实战:用 @dnd-kit 实现可拖拽、可排序的看板
test12026-10-174 次阅读
为什么选 @dnd-kit
原生 HTML5 拖拽 API 在移动端、可访问性和复杂交互上坑很多。@dnd-kit 用 Pointer 事件重写了一套拖拽内核,体积小、支持键盘操作和传感器自定义,是现在 React 拖拽的主流选择。
安装与最小骨架
npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
DndContext 提供拖拽上下文,SortableContext 负责可排序列表,useSortable 让单个条目具备拖拽能力。
可排序列表组件
import { useState } from 'react';
import {
DndContext, closestCenter, PointerSensor, useSensor, useSensors,
DragEndEvent,
} from '@dnd-kit/core';
import {
SortableContext, arrayMove, verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { SortableItem } from './SortableItem';
export function Board() {
const [items, setItems] = useState(['需求评审', '开发', '测试', '上线']);
const sensors = useSensors(
useSensor(PointerSensor, { activationConstraint: { distance: 5 } })
);
function handleDragEnd(event: DragEndEvent) {
const { active, over } = event;
if (!over || active.id === over.id) return;
setItems((prev) => {
const from = prev.indexOf(String(active.id));
const to = prev.indexOf(String(over.id));
return arrayMove(prev, from, to);
});
}
return (
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
<SortableContext items={items} strategy={verticalListSortingStrategy}>
{items.map((id) => <SortableItem key={id} id={id} />)}
</SortableContext>
</DndContext>
);
}
单个可排序条目
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
export function SortableItem({ id }: { id: string }) {
const { attributes, listeners, setNodeRef, transform, transition } =
useSortable({ id });
const style = {
transform: CSS.Transform.toString(transform),
transition,
};
return (
<li ref={setNodeRef} style={style} {...attributes} {...listeners}>
{id}
</li>
);
}
几个工程注意点
- activationConstraint 设 distance,避免点击误触发拖拽。
- 拖拽手柄建议单独绑定 listeners,整行可点击时不与排序冲突。
- 跨容器拖拽用 multiple containers,配合 onDragOver 做实时迁移。
- 列表数据用唯一 id 数组管理,拖拽结束用 arrayMove 重排即可,无需手动操作 DOM。
T
test1
文章作者
为什么选 @dnd-kit 原生 HTML5 拖拽 API 在移动端、可访问性和复杂交互上坑很多。@dnd-kit 用...
- 分类
- 技术
- 发布时间
- 2026-10-17
- 字数
- 约 2050 字
- 阅读
- 4 次
