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

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

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

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


🧱 列可见性切换

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

🧪 核心代码解析

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

tsx 复制代码
const [columns] = React.useState(() => [...defaultColumns]);

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

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

tsx 复制代码
const [columnVisibility, setColumnVisibility] = React.useState({});

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

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

tsx 复制代码
const table = useReactTable({
  data,
  columns,
  state: { columnVisibility },
  onColumnVisibilityChange: setColumnVisibility,
  getCoreRowModel: getCoreRowModel(),
});

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

⚙️ 4. UI 部分实现:

全选开关:

tsx 复制代码
<input
  type="checkbox"
  checked={table.getIsAllColumnsVisible()}
  onChange={table.getToggleAllColumnsVisibilityHandler()}
/>

单列开关:

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

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

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

代码地址🔗:Gitee

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

✨ 列排序

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

🔧 如何实现列顺序切换?

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

tsx 复制代码
const [columnOrder, setColumnOrder] = React.useState<ColumnOrderState>([]);

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

⚙️ 1. 步骤拆解:

初始化状态:

tsx 复制代码
const [columnOrder, setColumnOrder] = React.useState<ColumnOrderState>([])

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

⚙️ 2. 配置到表格中:

tsx 复制代码
const table = useReactTable({
  //...
  state: { columnOrder },
  onColumnOrderChange: setColumnOrder,
});

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

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

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

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

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

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

代码地址🔗:Gitee

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

🧀 列拖拽排序

🧲 用 DnD Kit 加持列排序交互

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

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

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

tsx 复制代码
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 的容器,它告诉系统:这一组元素是可以排序的,排序方式是"水平排列"。

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

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

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

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

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

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

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

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

tsx 复制代码
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 /> 组件,实现列单元格的同步拖拽动画:

tsx 复制代码
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 中,确保拖动时位置变化一致:

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

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

代码地址🔗:Gitee

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

相关推荐
独立开阀者_FwtCoder几秒前
"页面白屏了?别慌!前端工程师必备的排查技巧和面试攻略"
java·前端·javascript
慧一居士几秒前
Vite 完整功能详解与 Vue 项目实战指南
前端·vue.js
南岸月明几秒前
不聊主业,聊聊你们眼中的副业是什么样的?
前端
Kevin在掘金920146 分钟前
c#、.net、Fluent UI Blazor
前端
LovelyAqaurius7 分钟前
RSA加密算法:从数学魔法到现实守护
前端
Hilaku8 分钟前
说实话,React的开发体验,已经被Vue甩开几条街了
前端·javascript·vue.js
蛋黄蛋黄12 分钟前
微信表情怎么在自己的项目使用微信表情?-> [开源仓库]wechat-emoji
前端·github
汪子熙13 分钟前
错误剖析:net::ERR_HTTP2_PROTOCOL_ERROR 200 (OK) 的含义与解决之道
前端
猩猩程序员15 分钟前
Rust 1.88 稳定支持裸函数:更安全简洁的汇编函数写法
前端
艾克马斯奎普特16 分钟前
为什么响应性语法糖最终被废弃了?尤雨溪也曾经试图让你不用写 .value
前端·vue.js·代码规范