Table 表格
import { InternalTable, EXPAND_COLUMN, SELECTION_ALL, SELECTION_COLUMN, SELECTION_INVERT, SELECTION_NONE, Summary, TableSELECTION_COLUMN, TableSummaryCell, TableSummaryRow } from '@apollo-design/ui';数据表格,用于展示行列数据结构。
何时使用
- 当有大量结构化的数据需要展现时;
- 当需要对数据进行排序、搜索、分页、自定义操作等复杂行为时。
引入
import { Table } from '@apollo-design/ui';
代码演示
基础用法 #
基本使用:columns 定义列、data-source 提供数据;bodyCell 插槽自定义单元格渲染。
边框 #
bordered 展示表格内外边框。
紧凑型 #
size="middle" | "small" 两种紧凑形态。
可展开 #
#expandedRow 插槽 自定义展开内容;defaultExpandAllRows 默认全部展开。
行选择 #
row-selection 开启勾选列;v-model 形态用 selectedRowKeys 受控。
选择和操作 #
勾选列 + 操作列的组合:getCheckboxProps 按行禁用勾选,工具栏按钮读 selectedRowKeys 做批量操作;
选中行随数据删除同步清理,避免出现指向已删行的残留 key。
窄屏使用 scroll.x 保留完整列宽,横向滚动可访问操作列;键盘聚焦 Delete 时也会将按钮滚入视口。
单选(radio) #
row-selection.type="radio" 单选列。
树形数据展示 #
数据带 children 字段即自动成为树形表格(childrenColumnName 可换字段名)。
排序 #
列上声明 sorter 即开启排序(三态循环);defaultSortOrder 指定默认排序。
多重排序用 sorter: { compare, multiple: n }。
多列排序 #
sorter 的对象形态带 multiple 权重:数字越小优先级越高,多列同时排序按权重依次比较。
onChange 的第三个参数在多列激活时是数组。
筛选 #
列上声明 filters + onFilter 开启筛选下拉;filterMultiple 控制多选/单选;
filteredValue 受控。
筛选可搜索 #
列上 filterSearch 打开筛选下拉里的搜索框:true 按 value 直接匹配,
函数形态可自定义比对逻辑(第二参是筛选项 { text, value })。
自定义筛选菜单 #
列上 filterDropdown 完全接管筛选面板(拿到 setSelectedKeys / confirm / clearFilters 三件套),
配合 onFilter 做本地过滤、filterIcon 自定义漏斗图标的高亮态。
固定表头 #
scroll.y 给表体一个固定高度 ⇒ 表头吸顶、表体独立滚动。列宽建议显式声明,
否则表头与表体的列宽会各自按内容计算、滚动时对不齐。
固定列 #
列声明 fixed: 'left' | 'right' 固定列;横向内容超出时(scroll.x)固定列吸边并带阴影。
固定头和列 #
scroll 同时给 x 与 y:横向由 fixed: 'left' | 'right' 的列吸边,纵向表头吸顶。
固定列与滚动列的交界处会自动带阴影。
表头分组 #
列的 children 即多级表头(可嵌套任意层);带 children 的列只做分组、不渲染单元格。
分组表头同样支持 fixed 与 filters / sorter。
表格行/列合并 #
单元格合并靠列的 onCell:返回 { colSpan } 跨列、{ rowSpan } 跨行。
⚠️ 被跨掉的格子必须显式返回 0,否则后面的列会整体错位 —— 合并是「按格算」而不是「按列算」。
第二行的 Age 跨两列,覆盖返回 colSpan: 0 的 Home phone;Name 分别跨前三行和后两行,后两行的 Home phone 也纵向合并。
汇总行 #
使用 #summary 插槽与 Summary、TableSummaryRow、TableSummaryCell 命名组件渲染表尾汇总,通过 colSpan 合并列。命名组件也适用于模板自动引入。
自定义空状态 #
emptyText 覆盖空数据时的占位内容(VNode 或返回 VNode 的函数)。
需要跟页面其它空态保持一致时用它,而不是改全局 locale。
超出省略 #
列上 ellipsis 让超出列宽的内容单行省略。⚠️ 它依赖确定的列宽 ——
不给 width 时浏览器无从判断「超出」,省略不会生效。
远程加载数据 #
服务端分页的标准形态:pagination 受控(current / pageSize / total 都来自响应),
翻页在 change 里重新拉数据,loading 覆盖请求期。
示例用一个本地假接口代替真实请求 —— 保持离线可跑、结果确定。
粘性头部 #
sticky 让表头随页面滚动吸顶(区别于 scroll.y —— 那个是表体自己滚、表头不动)。
sticky 传对象时可指定 { offsetHeader, offsetScroll, getContainer }。
虚拟滚动 #
virtual 开启虚拟滚动(大表格场景):表体交给 @apollo-design/virtual-list,只渲染视口内的行。
scroll.y 给视口高度、scroll.x 给内容宽度 —— virtual 下二者必须是数值(否则按 1 / 500 兜底并告警)。
行与列的顺序调整 #
通过已有 onRow、列 onHeaderCell 接入浏览器原生拖放事件,拖动后更新受控 dataSource / columns 顺序,不依赖 React 或第三方拖拽运行时。行与列分别拖放;按钮提供可用键盘操作的同等调整方式,并支持重置。这是消费端组合示例,Table 没有新增内建拖拽 prop。
列默认值 #
使用 column 为全部列提供公共默认值,切换 align 可观察它只作用于未显式声明对齐方式的列。
可编辑单元格 #
在列 render 中渲染 Input 与 InputNumber,直接修改本地数据并统计编辑次数,支持一键重置。
树形数据 #
通过 childrenColumnName="subRows" 指定树形字段,并用 expandable.expandedRowKeys 受控展开,按钮可全部展开或收起。
树形筛选搜索 #
结合 filterMode="tree"、嵌套 filters 与 filterSearch 搜索分类,@change 会实时展示当前选中的筛选值。
容器内吸顶表头 #
在固定高度的滚动容器内使用 sticky,滚动时表头吸附在容器顶部,按钮可快速验证吸顶效果。
分页位置 #
使用 pagination.placement 同时在上方与下方渲染分页器,可切换位置并实时同步当前页码。
组件 Token #
Table 的 Component Token 以 --apollo-table-* CSS 变量输出;在容器上覆盖表头、行悬停、单元格内边距等变量即可定制,切换下拉框可对比默认与自定义主题。
动态设置 #
通过开关与下拉框实时切换 bordered、loading、showHeader、rowHoverable 与 size,表格上方的标签会同步显示当前配置。
可编辑行 #
点击「编辑本行」后整行切换为表单控件,可修改姓名、年龄与部门;保存后写回本地数据,取消则丢弃草稿并显示当前编辑状态。
省略与自定义 Tooltip #
列设置 ellipsis: { showTitle: false } 关闭原生 title,再在 render 中用 Tooltip 展示完整内容;切换下拉框可实时改变浮层方位。
展开行与吸附表头 #
在可滚动容器中同时启用 sticky 表头与 #expandedRow 插槽,滚动时表头保持吸附,展开行仍可独立控制。
表头与扩展区 #
title 接收渲染函数,可放置标题、数量和刷新按钮;footer 提供表格底部内容,排序与筛选变化会同步显示在页面上方。
嵌套子表格 #
#expandedRow 插槽 返回另一个 Table,展示每位客户的最近订单;按钮可展开或收起全部父行,子表格使用独立列与本地数据。
分页 #
受控 pagination 配置每页条数、快速跳页与总数展示;翻页或在每页条数下拉框中切换后,页面标签会同步当前页码与页大小。
重置筛选 #
筛选状态通过列上的 filteredValue 受控;点击「重置筛选」把两列的受控值置为 null,表格数据与筛选图标同步恢复,页面标签记录当前条件。
自定义选择项 #
通过 rowSelection.selections 提供「全选所有行」「清空选择」「仅选择偶数年龄」三个自定义菜单项,并保留禁用行;页面会显示当前选择与最近一次选择方式。
语义化样式 #
用 classNames 给根、标题、表头、表体与底部挂语义类名,用 styles 注入内联样式;切换 Blue / Warm 会同步改变边框、表头与行背景。
树形表格省略 #
树形数据配合固定列宽与 ellipsis:层级缩进和展开图标保留,超长名称与描述被截断并保留原生 title;按钮可展开或收起根节点。
drag-reorder 使用现有 onRow/onHeaderCell 钩子组合原生行/列拖放,受控更新数据和列顺序,并提供键盘可用的移动/重置按钮;不增加 Table 内建拖拽 API。
API
Table
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|---|---|---|---|---|
| bordered | 是否显示外边框和列边框 | boolean | false | |
| caption | 表格的可访问性标题(<caption>) |
VNodeChild | - | |
| columns | 列描述数据对象,见下表 | ColumnsType | - | |
| components | 覆盖表格元素的自定义渲染 | TableComponents | - | |
| dataSource | 数据数组 | T[] | - | |
| direction | 文本方向 | 'ltr' | 'rtl' |
- | |
| expandable | 展开配置,见下表 | ExpandableConfig | - | |
| expandIconColumnIndex | 展开按钮所在列的索引(建议将 Table.EXPAND_COLUMN 放入 columns) | number | - | |
| getPopupContainer | 下拉(筛选/选择器)渲染的父节点 | (triggerNode) => HTMLElement | ShadowRoot | - | |
| indentSize | 树形展示时每层的缩进宽度 | number | 15 | |
| loading | 页面是否加载中 | boolean | SpinProps | false | |
| locale | 默认文案设置,见下表 | TableLocale | - | |
| pagination | 分页器配置;设为 false 时隐藏 | false | TablePaginationConfig | 见下 | |
| rowClassName | 行的 className | string | (record, index) => string | - | |
| rowKey | 行 key 的取值字段或生成函数 | string | keyof T | (record) => key | 'key' | |
| rowSelection | 行选择配置,见下表 | TableRowSelection | - | |
| scroll | 横向/纵向滚动配置(含固定列/表头) | TableScrollConfig | - | |
| showHeader | 是否显示表头 | boolean | true | |
| size | 表格尺寸 | 'large' | 'middle' | 'small' |
'large' | |
| sortDirections | 支持的排序方式 | SortOrder[] | ['ascend', 'descend'] |
|
| sticky | 设置粘性表头 | boolean | TableSticky | - | |
| tableLayout | 表格布局算法(固定列/固定表头会自动置 fixed) | 'auto' | 'fixed' |
'auto'(固定列/表头时 'fixed') | |
| virtual | 是否开启虚拟滚动(需配合 scroll.x / scroll.y) |
boolean | false | |
| onRow | 行事件透传(click/doubleclick/mouseenter 等) | (record, index) => Record<string, unknown> | - | |
| onHeaderRow | 表头行事件透传 | (columns, index) => Record<string, unknown> | - |
virtual需要数值型scroll.x、scroll.y;估算行高由当前 Token 和 size 推导。
scroll.y 的数值以 CSS 像素为单位;0 保留明确的零高度表体。非虚拟表格也接受 CSS 长度字符串,移除 scroll.y 会取消高度限制。
Slots
| 名称 | 作用域 | 内容 |
|---|---|---|
| title / footer / summary / caption | { data: T[] } |
当前页标题、底部、汇总与可访问性标题 |
| emptyText | { data: T[], locale } |
空内容;存在时优先于 locale.emptyText,包括空槽 |
| expandedRow | { record: T, index, indent, expanded } |
展开行内容 |
| expandIcon | { prefixCls, record: T, expanded, expandable, onExpand } |
展开图标;调用 onExpand(record, event) 提议切换 |
| headerCell | { column, title } |
现有排序/筛选外壳内的表头内容 |
| bodyCell | { text, record: T, index, column, originNode } |
单元格内容,originNode 是数据 renderer 的当前结果 |
| paginationItemRender | { page, type, element } |
分页项 |
| paginationTotal | { total, range } |
分页总数 |
| paginationSizeChanger | PaginationSizeChangerInfo | 分页尺寸切换器 |
columns.render/title/filterDropdown/filterIcon/sortIcon 和选择列的 renderCell/columnTitle 属于每列/每项数据服务,继续保留。shouldCellUpdate(record, previousRecord) 控制数据 renderer 缓存;原生槽仍跟踪自己的 Vue 响应式依赖,替换列 renderer 或改变行索引会更新缓存。
汇总插槽可使用命名导出的 Summary、TableSummaryRow、TableSummaryCell;后两者分别对应 Summary.Row、Summary.Cell,便于原生模板和自动引入使用。
Emits 与控制状态
| 事件 | 参数 |
|---|---|
| change | (pagination, filters, sorter, { currentDataSource: T[], action }) |
| scroll | (event: Event),来自当前真实表体;虚拟表体也保留原生 target |
分页 current/pageSize、列 sortOrder/filteredValue、rowSelection.selectedRowKeys 和 expandable.expandedRowKeys 各有一个接受态来源。通知携带本次提议;父组件拒绝受控提议时,界面与缓存保持接受态,撤除控制后延续最近的接受值。选择和展开配置内的业务通知保留原有职责,不另加 Table v-model。
泛型与 Ref
原生模板从 dataSource: User[] 和 ColumnsType<User> 推导行类型,interface User 无需索引签名。程序化调用使用 h(Table<User>, props, slots);插槽可声明为 TableSlots<User>,引用使用 TableRef。
nativeElement() 返回内部表格根 HTMLElement;scrollTo({ top }) 或 scrollTo({ key, index, align, offset }) 操作当前表体。align 支持 start/center/end/nearest。自定义 components.body(data, { scrollbarSize, ref, onScroll }) 应把 ref 接到真实 HTMLElement,并把原生滚动事件传给 onScroll;该显式服务优先于内置虚拟表体。
自定义元素组件应转发原生 attrs 和 default 槽。虚拟 wrapper 需要单个 HTMLElement 根;多根/纯文本组件没有可测量的滚动容器,nativeElement 为 null。更换组件或其根节点后会重新绑定真实元素与观察资源。
迁移
顶层 title/footer/summary/expandedRowRender/expandIcon/emptyText,以及 expandable 内 expandedRowRender/expandIcon,改为上述具名槽;位置参数改为具名作用域。locale.emptyText 保留静态 VNodeChild,动态内容用 #emptyText。filterDropdownProps.dropdownRender 改用列的 filterDropdown 数据 renderer。onRow/onCell/onHeaderCell 返回 Vue 原生 attrs,例如 onKeydown;onChange/onScroll 通过 @change/@scroll 订阅。
选择配置的 getCheckboxProps 按 type 对应真实输入,checkbox/radio change 均为 (event: Event, checked: boolean);选择通知保留同一个原生事件。原生 class/style 落外层根;语义 styles 使用 Vue CSSProperties(含 undefined 与 --custom)。
ColumnsType(列描述)
columns 的每一项支持分组列(children)与普通列,ColumnGroupType | ColumnType。
onCell(record, rowIndex) 返回原生单元格属性,包含 colSpan、rowSpan 和事件监听。跨度为 0 时不渲染该格,其位置必须由另一格的跨度覆盖。
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| align | 列内容的对齐方式 | 'left' | 'right' | 'center' |
- |
| colSpan | 表头列合并(设 0 不渲染表头) | number | - |
| onCell | 单元格属性、合并跨度和原生事件 | (record: T, rowIndex) => Record<string, unknown> | - |
| onHeaderCell | 表头单元格事件透传 | (column) => Record<string, unknown> | - |
| defaultSortOrder | 默认排序顺序 | 'ascend' | 'descend' |
- |
| ellipsis | 超过宽度将自动省略(单行) | boolean | { showTitle?: boolean } | false |
| filters | 表头的筛选菜单项 | ColumnFilterItem[] | boolean | - |
| filterDropdown | 自定义筛选面板 | VNodeChild | (props) => VNodeChild | - |
| filterIcon | 自定义 filter 图标 | VNodeChild | (filtered) => VNodeChild | - |
| filterMode | 筛选菜单模式(树形/菜单) | 'tree' | 'menu' |
'menu' |
| filtered | 标识数据是否经过筛选,图标高亮 | boolean | false |
| filteredValue | 筛选的受控属性 | FilterValue | null | - |
| filterMultiple | 是否多选 | boolean | true |
| filterSearch | 筛选菜单中是否可搜索 | boolean | (input, record) => boolean | false |
| fixed | 列是否固定 | 'left' | 'right'(RTL 下 start/end) |
false |
| key | 列的稳定标识,用于排序、筛选与列复用 | string | - |
| responsive | 命中任一断点时显示该列 | Breakpoint[] | - |
| rowSpan | 行合并 | number | - |
| render | 生成复杂数据的渲染,位置参数 (value, record, index) |
(value, record, index) => VNodeChild | - |
| showSorterTooltip | 表头排序气泡提示 | boolean | SorterTooltipProps | true |
| sortOrder | 排序的受控属性 | 'ascend' | 'descend' | null |
- |
| sorter | 排序函数;true 由消费方处理排序 | boolean | CompareFn |
false |
| sortDirections | 支持的排序方式(覆盖 Table 级) | SortOrder[] | ['ascend', 'descend'] |
| title | 列头显示文字 | VNodeChild | ColumnTitle | - |
| width | 列宽度(固定列与 scroll.x 配合必填) | number | string | - |
| children | 分组列的子列 | ColumnsType | - |
| onFilter | 本地过滤函数 | (value, record) => boolean | - |
| onFilterDropdownOpenChange | 筛选面板展开/收起的回调 | (open) => void | - |
TableRowSelection(行选择)
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| checkStrictly | checkable 状态下父子节点是否关联 | boolean | true |
| columnTitle | 自定义选择列标题 | VNodeChild | - |
| columnWidth | 自定义选择列宽度 | number | string | - |
| fixed | 选择列是否固定 | boolean | 'left' | 'right' |
- |
| getCheckboxProps | 默认的复选框属性 | (record) => Record<string, unknown> | - |
| preserveSelectedRowKeys | 数据源变更后保留上一页选中项 | boolean | - |
| renderCell | 渲染选择单元格 | (checked, record, index, originNode) => VNodeChild | - |
| selectedRowKeys | 指定选中项的 key 数组(受控) | TableKey[] | - |
| selections | 自定义选择项(SELECTION_ALL / SELECTION_INVERT / SELECTION_NONE 等) |
SelectionItem[] | true | - |
| type | 多选或单选 | 'checkbox' | 'radio' |
'checkbox' |
| onChange | 选中项发生变化时的回调 | (selectedRowKeys, selectedRows, info) => void | - |
| onSelect | 用户手动选择/取消某行的回调(含 shift 联动 info) | (record, selected, selectedRows, nativeEvent) => void | - |
| onSelectAll | 全选/取消全选的回调 | (selected, selectedRows, changeRows) => void | - |
| onSelectInvert | 反选的回调 | (selectedRowKeys) => void | - |
| onSelectNone | 清空选择的回调 | () => void | - |
ExpandableConfig(展开)
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| childrenColumnName | 树形数据的子节点字段 | string | 'children' |
| columnTitle | 自定义展开列标题 | VNodeChild | - |
| columnWidth | 自定义展开列宽度 | number | string | - |
| defaultExpandAllRows | 初始时展开所有行 | boolean | false |
| defaultExpandedRowKeys | 默认展开的行 | TableKey[] | - |
| expandedRowClassName | 展开行的 className | string | (record, index, indent) => string | - |
| expandedRowKeys | 展开的行(受控) | TableKey[] | - |
| expandIconColumnIndex | 展开按钮所在列的索引 | number | - |
| fixed | 展开列的固定位置 | 'left' | 'right' | 'start' | 'end' |
- |
| indentSize | 树形缩进宽度 | number | 15 |
| rowExpandable | 行是否可展开 | (record) => boolean | - |
| showExpandColumn | 是否展示展开列 | boolean | true |
| onExpand | 展开行的回调 | (expanded, record) => void | - |
| onExpandedRowsChange | 展开的行变化时的回调 | (expandedRows) => void | - |
分页根节点的 class/style 放在 pagination.class / pagination.style;原 className 配置改用 class。
pagination(分页配置)
继承 Pagination 的全部 props,额外支持:
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| position | 指定分页显示的位置 | ['topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'] |
['bottomRight'] |
| hideOnSinglePage | 只有一页时是否隐藏分页器 | boolean | false |
pagination: false时隐藏分页器;默认每页 10 条(可传pageSize覆盖)。
TableLocale(默认文案)
| 参数 | 说明 | 类型 |
|---|---|---|
| emptyText | 无数据时的文案 | VNodeChild |
| filterConfirm | 筛选「确定」按钮文案 | string |
| filterReset | 筛选「重置」按钮文案 | string |
| filterEmptyText | 筛选菜单为空的文案 | string |
| selectAll | 全选行文案 | string |
| selectInvert | 反选文案 | string |
| selectNone | 清空选择文案 | string |
| selectionAll | 全部行选择文案 | string |
| sortTitle | 排序按钮的可访问名 | string |
| expand | 展开行的可访问名 | string |
| collapse | 折叠行的可访问名 | string |
| triggerDesc | 点击降序文案 | string |
| triggerAsc | 点击升序文案 | string |
| cancelSort | 取消排序文案 | string |
语义化与可访问性
- 支持通过
classNames/styles对root/section等语义槽位进行定制; - 排序按钮带
aria-sort,展开按钮带aria-expanded/aria-label(走 locale); caption提供表格的可访问名。
分页内容使用 #paginationItemRender="{ page, type, element }"、#paginationTotal="{ total, range }" 和 #paginationSizeChanger="info"。每个分页器接收当前作用域,支持顶部/底部及动态插槽;配置对象只放数据和业务事件,旧 itemRender/showTotal/sizeChangerRender 函数入口已移除。
当前主题变量
表头、排序、悬浮及筛选浮层的派生颜色跟随当前 ConfigProvider 主题,既有 Table 组件 Token 支持替换和移除,尺寸覆盖支持 0。原生根 CSS 变量优先于主题默认值;筛选 Portal 使用同一主题源。默认浅色的 40 条 CSS 变量声明保持不变。