DataTable 数据表格
轻量数据表格组件,提供排序、行选择与自定义渲染能力
DataTable 数据表格
基础用法
示例加载中...
行选择
示例加载中...
排序交互
可排序表头会暴露 aria-sort 状态,并支持鼠标点击、Enter 与 Space 在升序、降序、未排序之间切换。sortOnClient=false 时仍会触发 sortChange,但不会重排本地数据。
后台数据运维面板
在 Dashboard 数据区中,TxDataTable 负责主列表,TxPagination 负责页码切换,加载预览用 TxSkeleton / TxLayoutSkeleton 承接,避免空白等待。
数据运维面板
已通过本地 Nexus 页面截图验证的数据表格、分页与骨架加载组合。
示例加载中...
Records 场景
宽表 CRM 版式:表头吸顶、汇总行吸底、首列固定、部分选中三态、单元格原语组合。这些能力全部默认关闭,只有显式开启时才改变渲染。
组成这套版式的关键点:
maxHeight让表格自己成为滚动容器,表头与汇总行才有可吸附的参照;scrollX负责横向。不要把它塞进TxScroll默认模式——那是 transform 位移滚动,会让内部所有position: sticky失效。stickyHeader/stickyFooter开启后,表格在.is-sticky-shell内部切到border-collapse: separate。这不是风格选择:合并边框由表格绘制而非单元格绘制,吸顶的<th>一旦脱离就会丢掉自己的分隔线。切换只在该 class 内生效,bordered/striped在别处观感不变。- 汇总行来自
footer或footer-<key>插槽;不传插槽就完全不渲染<tfoot>。 - 全选框在部分选中时自动进入
indeterminate,向屏幕阅读器报告aria-checked="mixed"。 - 排序读时间戳字段,不要对「9 天前」这类可读文本做
localeCompare——那会把「1 年多前」排到「3 周前」和「9 天前」中间,还声称这是时间顺序。 sortCycle="bi"让表格永不回到未排序态,适合始终需要一个明确顺序的记录列表。
Records 记录表
吸顶表头与吸底汇总行、固定首列、选中高亮、三态全选,以及标签、圆点、链接三种单元格原语。
示例加载中...
行悬停与选中底色都暴露为 CSS 变量,因此这类「纸面」表格可以换成中性灰,而不必加 prop 或 !important:
.records-shell {
--tx-data-table-row-hover-bg: var(--tx-bui-hover);
--tx-data-table-row-selected-bg: color-mix(in srgb, var(--tx-bui-accent) 7%, var(--tx-bui-surface));
}
API
TxDataTable Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
columns | DataTableColumn[] | [] | 列配置 |
data | any[] | [] | 数据源 |
rowKey | keyof T | (row: T, index: number) => string | number | index | 行唯一标识 |
loading | boolean | false | 加载状态 |
emptyText | string | 'No data' | 空数据提示 |
striped | boolean | false | 斑马纹 |
bordered | boolean | false | 表格边框 |
hover | boolean | true | 悬浮高亮 |
interactiveRows | boolean | false | 让整行可聚焦(tabindex="0")并支持 Enter/Space 触发 rowClick;绑定了 rowClick 监听时会自动开启 |
selectable | boolean | false | 是否可选择 |
selectedKeys | Array<string | number> | [] | 选中 key 列表 |
defaultSort | { key: string; order: 'asc' | 'desc' | null } | null | 非受控模式的初始排序,之后由组件自己持有。与 sort 互斥,二选一 |
sort | { key: string; order: 'asc' | 'desc' | null } | null | - | 受控排序。传了它(包括传 null 表示未排序)组件就不再持有自身状态,只通过 update:sort 上报用户意图,并渲染父级回传的值。完全不传则走 defaultSort 的非受控模式 |
sortOnClient | boolean | true | 是否前端排序 |
sortCycle | 'tri' | 'bi' | 'tri' | 表头点击循环:tri 为升序→降序→取消排序,bi 为升序→降序→升序(永不取消) |
tableLayout | 'auto' | 'fixed' | 'auto' | 原生 table-layout 模式;列宽需要稳定时使用 fixed |
nowrap | boolean | false | 全局禁止表头与单元格内容换行 |
maxHeight | string | number | - | 限制表格高度并让组件自己成为纵向滚动容器。除非外层已有滚动祖先,否则 stickyHeader / stickyFooter 需要它才有吸附对象 |
scrollX | boolean | false | 让表格在组件内部横向滚动,宽表配固定列时需要 |
stickyHeader | boolean | false | 表头吸顶 |
stickyFooter | boolean | false | 汇总行吸底 |
rowClass | (row, index) => string | string[] | Record<string, boolean> | - | 按行追加 class,例如按状态给整行上色 |
highlightSelected | boolean | false | 给选中行加底色。默认关闭,既有表格的选中态仍只由复选框表达 |
DataTableColumn
| 字段 | 类型 | 说明 |
|---|---|---|
key | string | 列 key |
title | string | 表头文本 |
dataIndex | string | 数据字段名 |
width | string | number | 列宽 |
minWidth | string | number | 列最小宽度 |
maxWidth | string | number | 列最大宽度 |
auto | boolean | 强制列宽为 auto |
fixed | boolean | 'left' | 'right' | 固定列方向;true 等价于 'left'。未开启 scrollX / maxHeight 时,存在固定列会让根元素从 overflow: hidden 切到 overflow: visible,横向滚动需由外层容器提供,否则 sticky 偏移无处附着;开启 scrollX 后由组件自己承担这个滚动容器。 |
nowrap | boolean | 禁止当前列换行 |
align | 'left' | 'center' | 'right' | 对齐方式 |
sortable | boolean | 是否可排序 |
sorter | (a, b) => number | 自定义排序器 |
format | (value, row, index) => string | 默认文本格式化 |
headerClass | string | 表头 class |
cellClass | string | 单元格 class |
Events
| 事件名 | 参数 | 说明 |
|---|---|---|
update:selectedKeys | (keys) | 选中变化 |
selectionChange | (keys) | 选中变化 |
sortChange | (sort) | 排序变化 |
update:sort | (sort) | 排序变化;受控与非受控模式都会触发,配合 sort 使用 |
rowClick | ({ row, index }) | 行点击 |
Slots
| 名称 | 说明 |
|---|---|
header-<columnKey> | 自定义表头;接收 { column, sorted, order, toggle }。sorted 表示该列是否为当前排序列,order 为方向(非当前列时为 null),toggle 按配置的循环推进该列 |
cell-<columnKey> | 自定义单元格;接收 { row, column, value, index } |
footer | 汇总行的整行内容,由使用方自己提供 <td>,因此可以跨列合并。提供任一 footer 插槽才会渲染 <tfoot> |
footer-<columnKey> | 按列填充汇总单元格;接收 { column, data }。与 footer 同时存在时以 footer 为准 |
empty | 无展示行且 loading=false 时渲染的空状态 |
最佳实践
- 业务列表必须传稳定
rowKey;需要跨页保留选择时,用业务 id 驱动selectedKeys,不要依赖默认 index。 - 可排序列支持点击、Enter 与 Space;远程排序时设置
sortOnClient=false并监听sortChange。 tableLayout="fixed"配合显式width/minWidth,能避免运维表格在加载或排序时宽度跳动。- 固定列优先使用数值 px 的
width或minWidth;sticky 偏移会根据这些值计算。 - 横向滚动二选一:开
scrollX让组件自己成为滚动容器,或者维持默认、把表格包进外层overflow-x: auto容器。两种方式都能给 sticky 列提供可滚动的参照,但不要两层都滚。 - 需要吸顶表头或吸底汇总行时必须给
maxHeight(或确保外层已有滚动祖先),否则没有可吸附的对象;滚动容器不能是 transform 位移式的(如默认模式的TxScroll),那会让 sticky 整体失效。 - 排序请基于时间戳、序号这类可比较字段,不要对格式化后的相对时间文本排序。
- 自定义单元格要保留可读文本或状态徽标文本,因为可排序表头会通过
aria-sort暴露状态。 - 外壳按圆角裁切,因此组件会去掉表格最后一段末行的下边框;带汇总
tfoot时,分隔正文与汇总的那条线仍然保留。自定义单元格边框时请一并处理,否则表格底部会多出一条横线。
审阅说明
- 可访问性说明:
TxDataTable渲染原生表格;可排序表头使用scope="col"、aria-sort、键盘焦点,以及 Enter/Space 处理器。 - 类型:
rowKey声明为keyof T或返回字符串/数字的回调;sortChange可触发DataTableSortState或null。 - 实测覆盖: 组件测试覆盖表头和行渲染、指针排序与键盘
aria-sort状态切换、选择事件,以及 layout/nowrap/auto/固定列样式;末行分隔线的重置直接针对 SFC 源码断言,因为 vitest 不会执行<style>块。
Source
- Component source:
packages/tuffex/packages/components/src/data-table/src/TxDataTable.vue。 - Type contracts:
packages/tuffex/packages/components/src/data-table/src/types.ts导出DataTableProps、DataTableColumn、排序状态、行 key 与 emit 类型。 - Coverage:
packages/tuffex/packages/components/src/data-table/__tests__/data-table.test.ts覆盖表头和行渲染、指针与键盘排序(包括aria-sort)、选择事件、layout/nowrap/auto/固定列样式,以及末行分隔线的重置。
查看源码
packages/tuffex/packages/components/src/data-table/index.ts