跟着官方示例学习 @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),即最终渲染到表格中的“最底层的列”。
🔔 对官方示例代码可能存在一些删减的情况
代码地址🔗: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 应用到表格中
🔔 对官方示例代码可能存在一些删减的情况
代码地址🔗: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
,我们传入当前列的 ID
,Dnd Kit
会帮我们处理拖拽逻辑,transform
会让列在拖动时产生动画过渡。
⚙️ 2. 将所有列头包进 <SortableContext />
SortableContext
是 DnD 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>
🔔 对官方示例代码可能存在一些删减的情况
代码地址🔗:Gitee
官方代码地址🔗: @tanStack/react-table