跟着官方示例学习 @tanStack-table --- Row Dnd

🌲系列一:跟着官方示例学习 @tanStack-table --- Basic

🌲系列二:跟着官方示例学习 @tanStack-table --- Header Groups

🌲系列三:跟着官方示例学习 @tanStack-table --- Column Filters

🌲系列四:跟着官方示例学习 @tanStack-table --- Column Ordering

🌲系列五:跟着官方示例学习 @tanStack-table --- Sticky Column Pinning

🌲系列六:跟着官方示例学习 @tanStack-table --- Column Sizing

🌲系列七:跟着官方示例学习 @tanStack-table --- Expanding

🌲系列八:跟着官方示例学习 @tanStack-table --- Pagination


还记得在之前的文章中,我们已经实现了列排序 跟着官方示例学习 @tanStack-table --- Column Ordering,今天我们就来实现让用户可以随心所欲地拖动表格的每一行,就像排乐高积木一样!

我们会用到 @dnd-kit ------ 一个强大又灵活的 React 拖拽库,和 TanStack Table 配合起来简直是天作之合!

🎛️ 为什么需要自定义 rowId

TanStack Table 默认使用数组索引作为 row.id。这对一般场景没问题,但在拖拽排序中,索引会变化,导致状态错乱。

我们必须提供一个稳定的 ID,比如:

tsx 复制代码
useReactTable({
  data,
  columns,
  getRowId: (row) => row.userId,
});

✅ 这是整个拖拽功能的基石。如果你忽略它,调试时就会遇到:"为什么我拖了,但数据没变?" 的迷之场景。

✨ 拖拽的三要素:传感器、排序策略和回调处理

在正式开始前,我们来看看我们需要哪些基础结构:

tsx 复制代码
const sensors = useSensors(
  useSensor(MouseSensor, {}),
  useSensor(TouchSensor, {}),
  useSensor(KeyboardSensor, {})
);

这是 dnd-kit 的"感知器"们,负责检测你是在鼠标拖、手指划、还是键盘控制。

🧲 拖拽把手 Cell

我们需要一个专属的拖动按钮------小小一枚 🟰 图标,它其实是个按钮,绑定了拖拽事件。

tsx 复制代码
const RowDragHandleCell = ({ rowId }: { rowId: string }) => {
  const { attributes, listeners } = useSortable({ id: rowId });
  return <button {...attributes} {...listeners}>🟰</button>;
};

📌 这个组件会被插入到表格的第一列,用来当"拖动的起点"。

⌚️ 可拖拽的表格行 DraggableRow

每一行都要支持拖动,这时候我们就得使用 useSortable<tr> 包一层魔法:

tsx 复制代码
const DraggableRow = ({ row }: { row: Row<Person> }) => {
  const { transform, transition, setNodeRef, isDragging } = useSortable({
    id: row.original.userId,
  });

  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isDragging ? 0.8 : 1,
    zIndex: isDragging ? 1 : 0,
    position: "relative",
  };

  return (
    <tr ref={setNodeRef} style={style}>
      {row.getVisibleCells().map((cell) => (
        <td key={cell.id} style={{ width: cell.column.getSize() }}>
          {flexRender(cell.column.columnDef.cell, cell.getContext())}
        </td>
      ))}
    </tr>
  );
};

当你开始拖拽时,isDragging 会变成 true,我们可以让这行有些"飘起来"的视觉效果,视觉上的"提起感"来自于 opacity + zIndex + boxShadow

🔗 SortableContext 是桥梁

我们用 SortableContext 包住了所有 <tr>

tsx 复制代码
<SortableContext items={dataIds} strategy={verticalListSortingStrategy}>
  {table.getRowModel().rows.map((row) => (
    <DraggableRow key={row.id} row={row} />
  ))}
</SortableContext>

这是 dnd-kit 的核心设计:告诉引擎,谁可以被排序、按什么方式排序。

  • items: 是 rowID 列表,它必须与你的 data 顺序一致

  • strategy: 排序策略。常用的有:

    • verticalListSortingStrategy:垂直列表

    • rectSortingStrategy:网格布局

🧠 处理拖拽结束后的排序逻辑

拖动行的目的当然是为了重新排序,所以我们需要在 onDragEnd 中做个数据重排:

tsx 复制代码
function handleDragEnd(event: DragEndEvent) {
  const { active, over } = event;
  if (active && over && active.id !== over.id) {
    setData((data) => {
      const oldIndex = dataIds.indexOf(active.id);
      const newIndex = dataIds.indexOf(over.id);
      return arrayMove(data, oldIndex, newIndex);
    });
  }
}

🏗️ 整体结构 App

别忘了,SortableContext 需要包裹可拖动的元素区域,items 要传入对应的 id 列表,用于排序。

我们的表格组件最后就像这样:

tsx 复制代码
<DndContext
  collisionDetection={closestCenter}
  modifiers={[restrictToVerticalAxis]}
  onDragEnd={handleDragEnd}
  sensors={sensors}
>
  <table>
    <thead>{/* 渲染头部 */}</thead>
    <tbody>
      <SortableContext items={dataIds} strategy={verticalListSortingStrategy}>
        {table.getRowModel().rows.map((row) => (
          <DraggableRow key={row.id} row={row} />
        ))}
      </SortableContext>
    </tbody>
  </table>
</DndContext>

🔔 对官方示例代码可能存在一些删减的情况

代码地址🔗:Gitee

官方代码地址🔗: @tanStack/react-table

相关推荐
鹏北海6 分钟前
micro-app 微前端项目部署指南
前端·nginx·微服务
发现一只大呆瓜9 分钟前
虚拟列表:从定高到动态高度的 Vue 3 & React 满分实现
前端·vue.js·react.js
css趣多多13 分钟前
add组件增删改的表单处理
java·服务器·前端
证榜样呀18 分钟前
2026 大专计算机专业必考证书推荐什么
大数据·前端
蓝帆傲亦26 分钟前
前端性能极速优化完全指南:从加载秒开体验到丝滑交互
前端·交互
鱼毓屿御38 分钟前
如何给用户添加权限
前端·javascript·vue.js
JustHappy41 分钟前
「web extensions🛠️」有关浏览器扩展,开发前你需要知道一些......
前端·javascript·开源
何中应1 小时前
nvm安装使用
前端·node.js·开发工具
全栈探索者1 小时前
列表渲染不用 map,用 ForEach!—— React 开发者的鸿蒙入门指南(第 4 期)
react.js·harmonyos·arkts·foreach·列表渲染
雯0609~1 小时前
hiprint:实现项目部署与打印3-vue版本-独立出模板设计与模板打印页面
前端·vue.js·arcgis