news 2026/6/15 16:03:04

dnd-kit 实现表格拖拽排序

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
dnd-kit 实现表格拖拽排序

需求:用户可以拖拽表格行来调整条款顺序。

为什么选 @dnd-kit?

市面上常见的拖拽库:

  • react-dnd:太老了,API 很复杂
  • react-beautiful-dnd:已经不维护了,React 19 不兼容
  • react-sortable-hoc:API 过时,不支持 React 18+ 并发特性
  • react-grid-layout:太重了,功能太多
  • @dnd-kit:轻量、现代、React 19 完美兼容

我最后选了@dnd-kit,因为:

  1. 体积小(tree-shakeable)
  2. 性能好(用 CSS transform 而不是修改 DOM)
  3. 支持触摸屏
  4. TypeScript 支持好
基础实现

首先安装依赖:

npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities

然后用DndContext包裹表格:

import { DndContext, PointerSensor, useSensor, useSensors } from '@dnd-kit/core'; import { arrayMove, SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable'; import { restrictToVerticalAxis } from '@dnd-kit/modifiers'; import { CSS } from '@dnd-kit/utilities'; // 拖拽传感器 const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 1, // 移动 1px 后才开始拖拽,防止误触 }, }), ); // 拖拽结束 const onDragEnd = ({ active, over }) => { if (active.id !== over?.id) { const activeIndex = clauseList.findIndex(i => i.key === active.id); const overIndex = clauseList.findIndex(i => i.key === over?.id); const newClauseList = arrayMove(clauseList, activeIndex, overIndex); setClauseList(newClauseList); } }; return ( <DndContext sensors={sensors} modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}> <SortableContext items={clauseList.map(i => i.key)} strategy={verticalListSortingStrategy} > <Table ... /> </SortableContext> </DndContext> );
但有个坑:Ant Design Table 的行怎么变成可拖拽的?

Ant Design Table 的行不是普通的<tr>,是内部封装的组件。我要自定义body.row

const Row = props => { const { attributes, listeners, setNodeRef, transform, transition, isDragging, setActivatorNodeRef } = useSortable({ id: props['data-row-key'], }); const style = { ...props.style, transform: CSS.Translate.toString(transform), // 关键:把 transform 转成 CSS transition, ...(isDragging ? { position: 'relative', zIndex: 9999 } : {}), // 拖拽时提升层级 }; const contextValue = useMemo( () => ({ setActivatorNodeRef, listeners }), [setActivatorNodeRef, listeners], ); return ( <RowContext.Provider value={contextValue}> <tr {...props} ref={setNodeRef} style={style} {...attributes} /> </RowContext.Provider> ); }; // 使用 <Table components={{ body: { row: Row }, }} ... />

这里有个坑:transform不是字符串,是对象,要用CSS.Translate.toString()转换。

还有个坑:拖拽手柄怎么实现?

我不希望整行都能拖拽,只希望点击某个按钮才能拖。这样可以防止误操作。

RowContext传递 listeners:

const RowContext = React.createContext({}); const Row = props => { // ... const contextValue = useMemo( () => ({ setActivatorNodeRef, listeners }), [setActivatorNodeRef, listeners], ); return ( <RowContext.Provider value={contextValue}> <tr {...props} ref={setNodeRef} style={style} {...attributes} /> </RowContext.Provider> ); }; // 拖拽手柄组件 const DragHandle = () => { const { setActivatorNodeRef, listeners } = useContext(RowContext); return ( <MenuOutlined ref={setActivatorNodeRef} style={{ cursor: 'move' }} {...listeners} // 只在手柄上绑定 listeners /> ); }; // 在 columns 里使用 const columns = [ { key: 'sort', render: () => <DragHandle />, }, // ... ];

这样只有点击拖拽手柄时才能拖拽,整行点击不会误触。

最后的效果

拖拽流畅,性能很好,而且:

  1. 拖拽时有视觉反馈(半透明 + 提升层级)
  2. 只能垂直拖拽(restrictToVerticalAxis
  3. 防止误触(distance: 1+ 拖拽手柄)
几个踩坑总结
  1. Table 的行要自定义:用components.body.row
  2. transform 要转成 CSS:用CSS.Translate.toString()
  3. 拖拽手柄要用 Context:避免整行都能拖
  4. 限制拖拽方向:用restrictToVerticalAxis
  5. 防误触不能少distance: 1+ 拖拽手柄
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 12:50:44

智能体客服搭建流程实战:从零构建高可用AI对话系统

背景痛点&#xff1a;传统客服系统为何“听不懂人话” 过去两年&#xff0c;我先后接手过三套客服系统的重构。每次上线前&#xff0c;业务方最焦虑的问题几乎一模一样&#xff1a; 用户说“我要退钱”&#xff0c;系统却理解成“我要退款”&#xff0c;结果把用户引到售后工…

作者头像 李华
网站建设 2026/6/7 11:20:21

惊艳效果展示:RMBG-2.0人像抠图实测,发丝细节完美保留

惊艳效果展示&#xff1a;RMBG-2.0人像抠图实测&#xff0c;发丝细节完美保留 你有没有试过——一张普通的人像照片&#xff0c;上传后不到1秒&#xff0c;发丝边缘就清晰浮现&#xff0c;连耳后细小的绒毛都根根分明&#xff0c;背景被干净利落地切掉&#xff0c;透明通道完整…

作者头像 李华
网站建设 2026/6/15 13:38:39

手把手教你用Clawdbot将Qwen3-VL接入飞书办公

手把手教你用Clawdbot将Qwen3-VL接入飞书办公 你是不是也遇到过这样的场景&#xff1a;团队刚在星图平台私有化部署好Qwen3-VL:30B&#xff0c;模型能力很强&#xff0c;能看懂图片、理解表格、分析截图里的医学报告&#xff0c;甚至能根据产品图生成营销文案——但问题来了&a…

作者头像 李华
网站建设 2026/5/28 12:15:22

DLSS Swapper:让你的NVIDIA显卡性能提升30%的免费工具

DLSS Swapper&#xff1a;让你的NVIDIA显卡性能提升30%的免费工具 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper 你是否遇到过这样的情况&#xff1a;新买的3A大作在RTX 3060上只能跑到40帧&#xff0c;而游戏官方却迟…

作者头像 李华
网站建设 2026/6/15 14:17:39

Qwen3-Reranker-0.6B部署案例:省级政务知识图谱RAG重排序模块建设纪实

Qwen3-Reranker-0.6B部署案例&#xff1a;省级政务知识图谱RAG重排序模块建设纪实 1. 项目背景与目标定位 在省级政务知识图谱构建过程中&#xff0c;用户常通过自然语言提问获取政策解读、办事指南、法规条文等结构化信息。传统关键词检索BM25排序方式&#xff0c;在面对“跨…

作者头像 李华
网站建设 2026/6/15 14:18:44

BEYOND REALITY Z-Image惊艳效果:汗水微反光+皮肤湿度感+呼吸起伏暗示

BEYOND REALITY Z-Image惊艳效果&#xff1a;汗水微反光皮肤湿度感呼吸起伏暗示 1. 这不是“画出来”的人&#xff0c;是“呼吸着”站在你面前的人 你有没有试过盯着一张AI生成的人像&#xff0c;突然发现—— 那额角的一粒汗珠&#xff0c;在光线下微微发亮&#xff1b; 那鼻…

作者头像 李华