阅读视图

发现新文章,点击刷新页面。

跟着官方示例学习 @tanStack-table --- Column Ordering

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

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

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


🧱 列可见性切换

在实际项目中,我们经常需要根据用户需求隐藏不必要的列,或者让用户自由切换列的显示与否。例如:用户在查看员工信息时可能只关注姓名和职位,而不需要每次都看到访问次数或进度等辅助信息。

🧪 核心代码解析

⚙️ 1. 设置初始列定义:

const [columns] = React.useState(() => [...defaultColumns]);

通过 useState 列定义,确保列只初始化一次。

⚙️ 2. 控制列可见性的状态:

const [columnVisibility, setColumnVisibility] = React.useState({});

用于记录每个列的可见状态(key 是列 id,value 是 true 或 false)。

⚙️ 3. 在 useReactTable 中配置状态与回调:

const table = useReactTable({
  data,
  columns,
  state: { columnVisibility },
  onColumnVisibilityChange: setColumnVisibility,
  getCoreRowModel: getCoreRowModel(),
});

一旦用户勾选复选框,表格状态会同步更新并触发 UI 渲染。

⚙️ 4. UI 部分实现:

全选开关:

<input
  type="checkbox"
  checked={table.getIsAllColumnsVisible()}
  onChange={table.getToggleAllColumnsVisibilityHandler()}
/>

单列开关:

table.getAllLeafColumns().map((column) => (
  <input
    type="checkbox"
    checked={column.getIsVisible()}
    onChange={column.getToggleVisibilityHandler()}
  />
))

getAllLeafColumns API 🔗:获取所有叶子列(leaf columns),即最终渲染到表格中的“最底层的列”。

Jun-07-2025 14-54-35.gif

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

代码地址🔗:Gitee

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

✨ 列排序

在某些使用场景中,我们希望用户可以 动态调整表格列的顺序,以便根据业务需求进行自定义展示。

🔧 如何实现列顺序切换?

我们先来看最核心的两行代码:

const [columnOrder, setColumnOrder] = React.useState<ColumnOrderState>([]);

table.setColumnOrder(
  faker.helpers.shuffle(table.getAllLeafColumns().map(d => d.id))
);

⚙️ 1. 步骤拆解:

初始化状态:

const [columnOrder, setColumnOrder] = React.useState<ColumnOrderState>([])

columnOrder 是一个数组,表示当前列的显示顺序(每个元素是一个列 ID)。

⚙️ 2. 配置到表格中:

const table = useReactTable({
  //...
  state: { columnOrder },
  onColumnOrderChange: setColumnOrder,
});

当列顺序发生改变时,React Table会使用你提供的onColumnOrderChange回调更新状态。

⚙️ 3. 动态修改顺序(示例是随机打乱顺序):

table.setColumnOrder(
  faker.helpers.shuffle(table.getAllLeafColumns().map(d => d.id))
);
// 返回所有叶子列(最底层列), 得到它们的 ID 列表
getAllLeafColumns().map(d => d.id)

// 用于打乱顺序
faker.helpers.shuffle()

最终将新的顺序通过 setColumnOrder 应用到表格中

Jun-07-2025 16-30-44.gif

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

代码地址🔗:Gitee

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

🧀 列拖拽排序

🧲 用 DnD Kit 加持列排序交互

我们使用 @dnd-kit/core 来为表格添加拖拽能力

⚙️ 1. 每个列头变成可拖拽单元

我们创建了一个组件 <DraggableTableHeader />,它包裹住了每一个 <th>,并绑定了拖拽行为:

const DraggableTableHeader = ({ header }) => {
  const { setNodeRef, listeners, attributes, transform, isDragging } = useSortable({ id: header.column.id });

  const style = {
    transform: CSS.Translate.toString(transform),
    opacity: isDragging ? 0.8 : 1,
    //...
  }

  return (
    <th ref={setNodeRef} style={style}>
      {header.isPlaceholder
        ? null
        : flexRender(header.column.columnDef.header, header.getContext())}
      <button {...attributes} {...listeners}>🟰</button>
    </th>
  )
}

这个组件使用了 useSortable,我们传入当前列的 IDDnd Kit 会帮我们处理拖拽逻辑,transform 会让列在拖动时产生动画过渡。

⚙️ 2. 将所有列头包进 <SortableContext />

SortableContextDnD Kit 的容器,它告诉系统:这一组元素是可以排序的,排序方式是“水平排列”。

<SortableContext items={columnOrder} strategy={horizontalListSortingStrategy}>
  {headerGroup.headers.map(header => (
    <DraggableTableHeader key={header.id} header={header} />
  ))}
</SortableContext>

其中 items 是当前的列顺序(用 ID 表示),strategy 选择横向排序。

⚙️ 3. 配置 DndContext 管理拖拽行为

最外层我们包了一个 <DndContext>,这是 DnD Kit 的顶级组件,用于统一管理拖拽逻辑:

<DndContext
  sensors={sensors}
  collisionDetection={closestCenter}
  modifiers={[restrictToHorizontalAxis]}
  onDragEnd={handleDragEnd}
>
  {/* 表格渲染 */}
</DndContext>

我们使用 closestCenter 判断碰撞区域,使用 restrictToHorizontalAxis 限制只能左右拖动。

⚙️ 4. 拖拽完成后更新 columnOrder

当用户释放拖拽时,handleDragEnd 会被触发:

function handleDragEnd(event: DragEndEvent) {
  const { active, over } = event
  if (active && over && active.id !== over.id) {
    setColumnOrder((old) => {
      const oldIndex = old.indexOf(active.id)
      const newIndex = old.indexOf(over.id)
      return arrayMove(old, oldIndex, newIndex)
    })
  }
}

通过 arrayMove 工具函数,我们调整列的顺序数组 columnOrder,表格会自动根据新的顺序重新渲染。

⚙️ 5. 同步拖动列单元格

为了更真实的拖拽体验,不只是 <th> 头部,单元格 <td> 也要一起动。通过 <DragAlongCell /> 组件,实现列单元格的同步拖拽动画:

const DragAlongCell = ({ cell }) => {
  const { setNodeRef, transform } = useSortable({ id: cell.column.id })
  const style = {
    transform: CSS.Translate.toString(transform),
    ...
  }
  return <td ref={setNodeRef} style={style}>{...}</td>
}

并为每一行的每一格 <td> 也包进 SortableContext 中,确保拖动时位置变化一致:

<tr>
  {row.getVisibleCells().map(cell => (
    <SortableContext key={cell.id} items={columnOrder} strategy={horizontalListSortingStrategy}>
      <DragAlongCell key={cell.id} cell={cell} />
    </SortableContext>
  ))}
</tr>

Jun-07-2025 16-17-07.gif

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

代码地址🔗:Gitee

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

❌