功能说明
管理数据集列表,支持当前页选择、固定名称列、列宽调整、三档密度、搜索与状态筛选。示例数据均为虚构。
用到的组件
| 组件 | 用途 |
|---|---|
| grid-layout | 页面外框:竖线容器、全屏横线与点阵分隔带 |
| checkbox / button / input | 选择、操作与编辑 |
| grid-toolbar | 顶部工具栏:搜索、筛选、列设置、密度各占一格 |
| bar-field | 搜索输入与快捷键提示 |
| bar-select | 状态筛选与负责人多选筛选 |
| grid-pagination | 底部翻页条:范围、每页条数、首尾页和跳页,与表格之间隔一条点阵小带 |
| segmented-control | 密度选择(只显示行数图标,在工具栏里是三个方格) |
| alert-dialog | 单行与批量删除确认 |
| dropdown-menu | 列设置与窄屏排序菜单 |
| empty / skeleton | 空状态与加载 |
| sheet | 桌面右侧详情、手机底部详情与编辑面板 |
安装
pnpm dlx shadcn@latest add https://yiui.dev/r/data-table-01.json安装入口是 app/data-table/page.tsx,替换其中示例数据与列定义即可。
用法
"use client"
import { DataTable } from "@/components/data-table-01/data-table"
const columns = [{ accessorKey: "name", header: "名称" }]
const data = [{ id: "1", name: "城市声景" }]
export default function Page() {
return <DataTable columns={columns} data={data} getRowId={(row) => row.id} />
}客户端与服务端模式
默认 mode="client" 在本地排序、筛选和分页。mode="manual" 时由使用方响应 onSortingChange、onGlobalFilterChange、onColumnFiltersChange 和 onPaginationChange,请求后更新 data 与 rowCount。请求期间传 loading,失败传 error 和 onRetry。
编辑与失败回滚
列 meta.editable 支持 text 与 number。编辑框就地替换内容,整格描主色实线框,下方贴一条提示条显示快捷键;meta.validate(value, row) 返回错误文字时提示条变红,编辑态保留。
onCellCommit({ rowId, columnId, value, row }) 可以返回 Promise。保存是乐观的:编辑框立刻关闭,格子右上角显示「保存中」,成功后显示「已保存」并淡出;Promise 拒绝时值回滚,格子标红,悬停或聚焦可看到错误,按 Enter 重新编辑会带回草稿。值没有变化时不会调用 onCellCommit。父层应在保存成功后同步数据;编辑使用 accessorKey 对应的顶层字段。示例模拟 600ms 请求,改成已有的名称会被拒绝。
行操作与主动编辑
通过 apiRef 获取 DataTableHandle,调用 startEditing(rowId, columnId) 开始单元格编辑,调用 openDetails(rowId) 打开详情。桌面详情从右侧展开,手机从底部展开。
import { DataTableRowActions } from "@/components/data-table-01/data-table-row-actions"
;<DataTableRowActions
label={row.name}
actions={[
{ label: "查看详情", onSelect: () => apiRef.current?.openDetails(row.id) },
{
label: "编辑名称",
onSelect: () => apiRef.current?.startEditing(row.id, "name"),
},
"separator",
{ label: "删除…", destructive: true, onSelect: () => setDeleting([row]) },
]}
/>每项可传 icon、shortcut;"separator" 插入分隔线。示例提供查看、编辑、复制编号、导出 CSV、归档与删除。删除和批量删除先确认,复制结果由读屏提示。选中行内控件后按 Shift+F10 或 ContextMenu 键打开该行菜单。
窄于 40rem 时状态筛选独占一行,隐藏色点和数量以保留完整状态文字;隐藏密度选择,给搜索与筛选留出空间。虚拟滚动仅显示总行数。
负责人筛选
示例通过 toolbar={(table) => ...} 插槽接入方条多选:插槽里的控件包一层 GridToolbarItem 成为工具栏的一格,用 owner 列的 filterFn 匹配选中负责人,更新筛选后回到第一页。每位负责人的计数来自完整数据集;窄容器隐藏此筛选。
示例
服务端分页
首次进入第 3 页固定失败,重试后成功。
一万行虚拟滚动
传 virtualization={{ height: 480, estimateRowHeight: 40 }},关闭分页,仅渲染视口附近的行。数据使用确定性公式生成。
手机
小于 40rem 的容器显示两行账目列表。通过行菜单打开全部字段详情,点击可编辑字段保存;长按编号栏进入多选,排序收进工具栏菜单。
状态与保存失败
切换加载、两种空状态及错误;名称输入「失败」后保存可观察回滚。
API
columns、data、getRowId 必填。排序、分页、全局筛选、列筛选、行选择均支持受控值、对应 default* 初值与 on*Change 回调。分页默认每页 10 条。
搜索框默认只显示图标,读屏名称取 labels.searchField;传 searchLabel="搜索" 可在图标前显示条内标签。statusFilter={{ columnId, options }} 在搜索框右侧显示状态下拉(方条下拉,选项带色点和数量,清除即全部),空字符串表示全部,它的 label 作为未选时的占位(如「全部状态」,不传时取 labels.all),tone 设置色点颜色(如 "var(--flow-green)")。toolbar、bulkActions(selected)、rowActions(row) 提供操作插槽;bulkActions 里的按钮文字包在 <span data-label> 中,窄容器只显示图标,header 可传入头部内容。manual 模式使用 counts 传入状态计数。onSelectAll 由使用方处理跨页全选,表头只选择当前页。labels 覆盖文案。
列 meta 支持 align、editable、validate、hideOnMobile、pinned、bar(数字比例条)、max(服务端模式的列最大值),列宽使用原生 size。detailCell(value, row) 定制详情字段的展示,例如完整时间。首个标记 pinned 的可见数据列固定。
文件职责:data-table.tsx 组装,data-table-toolbar.tsx 工具栏,data-table-pagination.tsx 分页,data-table-cell.tsx 编辑,types.ts 类型,config.ts 文案。根节点为 data-slot="data-table",滚动容器为 data-table-scroll,编辑格为 data-table-cell。
可访问性
| 按键 | 操作 |
|---|---|
| Tab | 聚焦排序、选择、编辑格与列宽手柄 |
| Enter / F2 / 双击 | 开始编辑 |
| Enter | 保存并聚焦下一行同列 |
| 点击别处 | 保存 |
| Tab / Shift+Tab | 保存并聚焦下一个 / 上一个可编辑格 |
| Esc | 放弃修改 |
| ← / →(列宽手柄) | 调整 16px |
表头提供 aria-sort,虚拟行提供 aria-rowindex,编辑错误通过 aria-describedby 关联。
注意事项
Table 固定使用 v8 API,调用函数添加 "use no memo",避免 React Compiler 缓存稳定可变对象读取。虚拟滚动建议固定行高。不提供多格粘贴、撤销与方向键网格导航。