展示类 · Table
表格
表格用于呈现结构化的数据内容,通常会伴随提供对数据进行操作(排序、搜索、分页……)的能力。

如何使用

往 Table 传入表头 columns 和数据 dataSource 进行渲染。
请为 dataSource 中的每个数据项提供一个与其他数据项值不同的 key,或者使用 rowKey 参数指定一个作为主键的属性名,表格的行选择、展开等绝大多数行操作功能都会使用到。

代码演示

基本表格

对于表格,最基本的两个参数为 dataSourcecolumns,前者为数据项,后者为每列的配置,二者皆为数组类型。

JSX 写法

你也可以使用 JSX 语法定义 columns,注意 Table 仅支持 columns 的 JSX 语法定义。你不能够使用任何组件包裹 Table.Column 组件。
注意事项
1. JSX 写法的表格暂时不支持 resizable 功能;
2. 使用 JSX 写法时,请不要与配置写法同时使用;如果同时使用,仅配置写法生效,不会进行聚合操作。

行选择操作

往 Table 传入 rowSelection 即可打开此功能。
  • 点击表头的选择框,会选择 dataSource 里所有不是 disabled 状态的行。选择所有行回调函数为 onSelectAll
  • 点击行的选择框会选中当前行。它的回调函数为 onSelect
注意:请务必为每行数据提供一个与其他行值不同的 key,或者使用 rowKey 参数指定一个作为主键的属性名。

自定义渲染

用户可以使用 Column.render 来自定义某一列单元格的渲染,该功能适用于需要渲染较为复杂的单元格内容时。

带分页组件的表格

表格分页目前支持两种模式:受控和非受控模式。
  • 受控模式下,分页的状态完全由外部传入,依据为是否往 Table 传入了 pagination.currentPage 这个字段。一般情况下,受控模式适用于远程拉取数据并渲染。
  • 非受控模式下,Table 默认会将传入的 dataSource 长度作为 total 传给 Pagination 组件,当然你也可以传入一个 total 字段来覆盖 Table 组件的取值,不过我们并不推荐用户在非受控分页模式下传入这个字段。
非受控时传入自定义的 pagination.total 字段在 >=0.25.0 版本后才支持

拉取远程数据

正常情况下,数据往往不是一次性获取的,我们会在点击页码、过滤器或者排序按钮时从接口重新获取数据,这种情况下请使用受控模式来处理分页。用户需往 Table 传入 pagination.currentPage 这个字段,此时分页组件的渲染完全依赖于传入的 pagination 对象。
注意事项
1. 非受控时,pagination 如果是对象类型则不推荐使用字面量写法,原因是字面量写法会导致表格渲染至初始状态(看起来像是分页器没有生效)。请尽量将引用型参数定义在 render 方法之外,如果使用了 hooks 请利用 useMemo 或 useState 进行存储;
2. 受控模式下,Table 不会对 dataSource 分页,请给 dataSource 传入当前页数据

固定列或表头

可以通过设置 column 的 fixed 属性以及 scroll.x 来进行列固定,通过设置 scroll.y 来进行表头固定。
  • 请确保表格内部的所有元素在渲染后不会对单元格的高度造成影响(例如含有未加载完成的图片等),这种情况下请给定子元素一个确定的高度,以此确保左右固定列单元格不会错乱。
  • 若列头与内容不对齐或出现列重复,请指定固定列的宽度 width。如果指定 width 不生效,请尝试建议留一列不设宽度以适应弹性布局,或者检查是否有超长连续字段破坏布局。
  • 建议指定 scroll.x 为大于表格宽度的固定值或百分比。推荐设置为 >=所有固定列宽之和+所有表格列宽之和 的固定数值。

带排序和过滤功能的表头

表格内部集成了过滤器和排序控件,用户可以通过在 Column 中传入 filters 以及 onFilter 开启表头的过滤器控件展示,传入 sorter 开启表头的排序控件的展示。
注意:请务必为每行数据提供一个与其他行值不同的 key,或者使用 rowKey 参数指定一个作为主键的属性名。

自定义筛选项渲染

1.1.0 版本后,支持往 column 中传入 renderFilterDropdownItem 自定义每个筛选项的渲染方式。
  • text: ReactNode 当前筛选项的文案;
  • value: any 当前筛选项的值;
  • checked: boolean 当前筛选项是否已经选中;
  • filteredValue: any[] 当前所有的筛选值;
  • level: number 当前筛选项所处层级,如果是嵌套的筛选项,该值会 >= 1;
  • filterMultiple: boolean 当前筛选项是否为多选。

可以展开的表格

注意事项
1. 自 0.27.0版本后,展开按钮会默认与第一列文案渲染在同一个单元格内,你可以通过往 Table 传入 hideExpandedColumn=false 将展开按钮单独作为一列渲染;
2. 请务必为每行数据提供一个与其他行值不同的 key,或者使用 rowKey 参数指定一个作为主键的属性名。

一般可展开行

如果需要渲染可以展开的表格,除了需要在Table传 expandedRowRender 这个方法外,还必须要指定 rowKey(默认为 key),Table 会根据 rowKey 取得行唯一标识符。
  • 如果 rowKeyFunction,则会把 rowKey(record) 的结果作为行唯一 ID
  • 如果 rowKeystring 类型,则会把 record[rowKey] 作为行唯一 ID

展开按钮渲染为单独列

版本:>=0.27.0
默认情况,展开按钮会与第列文案渲染在同一个单元格内,你可以通过传入 hideExpandedColumn={false} 来渲染为单独一列:

关闭某一行的可展开按钮渲染

版本:>=0.27.0
可传入 rowExpandable 方法,入参为 record,判断返回值是否为 false 来关闭某一行的可展开按钮的渲染。

树形数据展示

版本:>=0.27.0
表格支持树形数据的展示,当数据中有 children 字段时会自动展示为树形表格,如果不需要或使用其他字段可以用 childrenRecordName 进行配置。另外可以通过设置 indentSize 以控制每一层的缩进宽度。
注意:请务必为每行数据提供一个与其他行值不同的 key,或者使用 rowKey 参数指定一个作为主键的属性名。

树形数据简单示例

行可交换的树形数据

版本:>=0.27.0
你可以通过改变 dataSource 元素的顺序来实现行交换操作。

树形选择

版本:>=0.27.0
默认情况下,表格的行选中是各自独立的,你可以通过定义 selectedRowKeys 来模拟一个树形选中。

自定义行或单元格事件以及属性

  • 传入 onRow/onHeaderRow 可以定义表格或表头行的原生事件或属性。
  • 传入 column.onCell/column.onHeaderCell 可以定义表格或表头单元格原生事件或属性。
原则上 tr/td/th 上支持的属性或事件都能够被定义。例如下面这个例子:
  • 表头的 tr 定义了 onMouseEnter/onMouseLeave
  • 表格的 tr 定义了 className
  • 表格的第三行定义了 onClick

实现斑马纹样式

使用 onRow 给每行设置一个背景色,实现有斑马纹效果的表格。如果设置了固定列,可以通过 onCell 给每列设置一个背景色实现相同效果。

可伸缩列

版本 >= 0.15.0

基本伸缩列

对于一些内容比较多的列,可以选择打开伸缩列功能,在表头进行拉拽实现列宽的实时变化。
不过你需要注意一些参数:
  • resizable 设定为 true 或者一个 object
  • columns 里需要伸缩功能的列都要指定 width 这个字段(如果不传,该列不具备伸缩功能,且其列宽度会被浏览器自动调整)
不推荐与固定列同时使用,固定列需要指定 scroll.x,这约定了表格是有宽度范围的,而伸缩列会拓展列宽,这可能会导致表格对不齐

进阶的伸缩列

resizable 还能为一个 Object,包括三个事件方法:
  • onResize
  • onResizeStart
  • onResizeStop
分别触发于列宽改变中开始改变结束改变三个时机。开发者可以选择在这个时机修改 column,例如在拉拽时增加一个拖动时的竖线效果等,如下例。
本例中使用的 CSS 样式定义:

拖拽排序

使用自定义元素,我们可以集成 react-dnd 来实现拖拽排序。
本例中使用的 CSS 样式为:

表格分组

版本:>=0.29.0
对于一些数据需要分组展示的表格,可以传入 groupBy 定义分组规则,使用 renderGroupSection 来定义分组表头的渲染。
注意:请务必为每行数据提供一个与其他行值不同的 key,或者使用 rowKey 参数指定一个作为主键的属性名。

虚拟化表格

虚拟化可用于需要渲染大规模数据的场景,通过配置 virtualized 参数来开启这个功能。需要注意的是:
  • 必须传递 scroll.y(number) 与 style.width(number);
  • 需要传递每行的高度 virtualized.itemSize(不传时普通行高默认为 56,组头行高默认为 56),可以为如下类型:
    • number
    • (index, { sectionRow?: boolean, expandedRow?: boolean }) => number
  • 表格分组虚拟化需要版本 >= 0.37.0
  • Semi Table 底层借助了 react-window 的能力来实现虚拟化,因此 react-window VariableSizeList 所支持的其他参数也可以通过 virtualized(object)传入,例如 overscanCount
  • 如果需要使用 VariableSizeList 的 API,可以传入getVirtualizedListRef 获取对应 ref,需要版本 >= 1.20
以下为渲染 1000 条数据的示例。

无限滚动

基于虚拟化特性,通过传入 virtualized.onScroll 我们可以实现无限滚动加载数据。

受控的动态表格

完全自定义渲染

版本:>=0.34.0
一般情况下,使用 Column.render 即可,但是你也可以通过传递 Column.useFullRender=true 来开启完全自定义渲染模式,此时复选框按钮、展开按钮、缩进等组件将会透传至 Column.titleColumn.render 方法中,你可以进一步来定义表头和单元格的内容渲染方式。
其中 Column.title 接受的入参为:
Column.render 第四个入参为一个object,结构如下:
下方的例子则是将复选框与内容渲染至同一单元格和表头中。

表头合并

版本:>=1.1.0
用户可以通过表头合并功能进行表头的分组,表头合并支持与固定列、虚拟化、数据分组、列伸缩等功能复合使用,也同时支持 JSX 或者配置式写法。

合并表头配置式写法

合并表头 JSX 写法

行列合并

  • 表头除了通过 children 写法进行合并外,可通过设置 column.colSpan 进行表头的列合并。
  • 表格支持行/列合并,使用 render 里的单元格属性 colSpan 或者 rowSpan 设值为 0 时,设置的表格不会渲染。

API 参考

Table

属性说明类型默认值版本
bordered是否展示外边框和列边框booleanfalse
childrenRecordName树形表格dataSource中每行元素中表示子级数据的字段,默认为childrenstring'children'
className最外层样式名string
clickGroupedRowToExpand点击分组表头行时分组内容展开或收起boolean0.29.0
columns表格列的配置描述,详见ColumnColumn[][]
dataSource数据RecordType[][]
defaultExpandAllRows默认是否展开所有行,动态加载数据时不生效booleanfalse
defaultExpandAllGroupRows默认是否展开分组行,动态加载数据时不生效booleanfalse1.30.0
defaultExpandedRowKeys默认展开的行 key 数组,,动态加载数据时不生效Array<*>[]
empty无数据时展示的内容ReactNode'暂无数据'
expandCellFixed展开图标所在列是否固定,与 Column 中的 fixed 取值相同boolean|stringfalse
expandIcon自定义展开按钮,传 false 关闭默认的渲染boolean | ReactNode
| (expanded: boolean) => ReactNode
expandedRowKeys展开的行,传入此参数时行展开功能将受控(stringnumber)[]
expandedRowRender额外的展开行(record: object, index: number, expanded: boolean) => ReactNode
expandAllRows是否展开所有行booleanfalse1.30.0
expandAllGroupRows是否展开分组行booleanfalse1.30.0
expandRowByClick点击行时是否展开可展开行booleanfalse1.31.0
footer表格尾部ReactNode
|(pageData: object) => ReactNode
getVirtualizedListRef返回虚拟化表格所用VariableSizeList的ref,仅在配置virtualized时有效(ref: React.RefObject) => void1.20.0
groupBy分组依据,一般为 dataSource 元素中某个键名或者返回值为字符串、数字的一个方法string|number
|(record: RecordType) => string|number
0.29.0
hideExpandedColumn当表格可展开时,展开按钮默认会与第一列文案渲染在同一个单元格内,设为false时默认将展开按钮单独作为一列渲染booleantrue
indentSize树形结构 TableCell 的缩进大小number20
loading页面是否加载中booleanfalse
pagination分页组件配置boolean|TablePaginationPropstrue
prefixCls样式名前缀string
renderGroupSection表头渲染方法(groupKey?: string | number, group?: string[] | number[]) => ReactNode0.29.0
renderPagination自定义分页器渲染方法(paginationProps?: TablePaginationProps) => ReactNode1.13.0
resizable是否开启伸缩列功能,需要进行伸缩的列必须要提供 width 的值boolean|Resizablefalse
rowExpandable传入该参数时,Table作行渲染时会调用该函数,返回值用于判断该行是否可展开,返回值为 false 时关闭可展开按钮的渲染(record: object) => boolean0.27.0
rowKey表格行 key 的取值,可以是字符串或一个函数string
|(record: RecordType) => string
'key'
rowSelection表格行是否可选择,详见 rowSelectionobject-
scroll表格是否可滚动,配置滚动区域的宽或高,详见 scrollobject-
showHeader是否显示表头booleantrue
size表格尺寸,影响表格行 padding"default"|"middle"|"small""default"1.0.0
title表格标题ReactNode
|(pageData: RecordType[]) => ReactNode
virtualized虚拟化配置Virtualizedfalse0.33.0
virtualized.itemSize每行的高度number|(index: number) => number560.33.0
virtualized.onScroll虚拟化滚动回调方法( scrollDirection?: 'forward' | 'backward', scrollOffset?: number, scrollUpdateWasRequested?: boolean ) => void0.33.0
onChange分页、排序、筛选变化时触发({ pagination: TablePaginationProps,
filters: Array<*>, sorter: object, extra: any }) => void
onExpand点击行展开图标时进行触发(expanded: boolean, record: RecordType, DOMEvent: MouseEvent) => void第三个参数 DOMEvent 需版本 >=0.28.0
onExpandedRowsChange展开的行变化时触发(rows: RecordType[]) => void
onGroupedRow类似于 onRow,不过这个参数单独用于定义分组表头的行属性(record: RecordType, index: number) => object0.29.0
onHeaderRow设置头部行属性,返回的对象会被合并传给表头行(columns: Column[], index: number) => object
onRow设置行属性,返回的对象会被合并传给表格行(record: RecordType, index: number) => object
一些上面用到的类型定义:
RecordType 为 Table 和 Column 的泛型参数,默认为 object 类型。你可以这样使用 RecordType:

onHeaderRow / onRow用法

onHeaderRow 中可以返回 th 支持的属性或者事件 onRow 中可以返回 tr 支持的属性或者事件

Column

属性说明类型默认值版本
align设置列的对齐方式'left' | 'right' | 'center''left'
className列样式名string
children表头合并时用于子列的设置Column[]
colSpan表头列合并,设置为 0 时,不渲染number
dataIndex列数据在数据项中对应的 key,使用排序或筛选时必传string
defaultFilteredValue筛选的默认值,值为已筛选的 value 数组any[]2.5.0
defaultSortOrder排序的默认值,可设置为 'ascend'|'descend'|falseboolean| stringfalse1.31.0
filterChildrenRecord是否需要对子级数据进行本地过滤,开启该功能后如果子级符合过滤标准,父级即使不符合仍然会保留boolean0.29.0
filterDropdown可以自定义筛选菜单,此函数只负责渲染图层,需要自行编写各种交互ReactNode
filterDropdownProps透传给 Dropdown 的属性,详情点击Dropdown APIobject
filterDropdownVisible控制 Dropdown 的 visible,详情点击Dropdown APIboolean
filterIcon自定义 filter 图标boolean|ReactNode|(filtered: boolean) => ReactNode
filterMultiple是否多选booleantrue
filteredValue筛选的受控属性,外界可用此控制列的筛选状态,值为已筛选的 value 数组any[]
filters表头的筛选菜单项Filter[]
fixed列是否固定,可选 true(等效于 left) 'left' 'right'boolean|stringfalse
keyReact 需要的 key,如果已经设置了唯一的 dataIndex,可以忽略这个属性string
render生成复杂数据的渲染函数,参数分别为当前行的值,当前行数据,行索引,@return 里面可以设置表格行/列合并(text: any, record: RecordType, index: number, { expandIcon?: ReactNode }) => object|ReactNode
renderFilterDropdownItem自定义每个筛选项渲染方式,用法详见自定义筛选项渲染({ value: any, text: any, onChange: Function, level: number, ...otherProps }) => ReactNode-1.1.0
sortChildrenRecord是否对子级数据进行本地排序boolean0.29.0
sortOrder排序的受控属性,外界可用此控制列的排序,可设置为 'ascend'|'descend'|falseboolean| stringfalse
sorter排序函数,本地排序使用一个函数(参考 Array.sort 的 compareFunction),需要服务端排序可设为 trueboolean|(r1: RecordType, r2: RecordType) => numbertrue
title列头显示文字。传入 function 时,title 将使用函数的返回值;传入其他类型,将会和 sorter、filter 进行聚合ReactNode|({ filter: ReactNode, sorter: ReactNode, selection: ReactNode }) => ReactNodeFunction 类型需要0.34.0
useFullRender是否完全自定义渲染,用法详见完全自定义渲染booleanfalse0.34.0
width列宽度string | number
onCell设置单元格属性(record: RecordType, rowIndex: number) => object
onFilter本地模式下,确定筛选的运行函数(filteredValue: any[], record: RecordType) => boolean
onFilterDropdownVisibleChange自定义筛选菜单可见变化时回调(visible: boolean) => void
onHeaderCell设置头部单元格属性(column: RecordType, columnIndex: number) => object
一些上面用到的类型定义:

Column.onCell / onHeaderCell 用法

onRowonHeaderRow类似,在 column.onCell column.onHeaderCell 中也能返回 td/th 支持的属性或事件

rowSelection

属性说明类型默认值版本
className所处列样式名string
disabled表头的 Checkbox 是否禁用booleanfalse0.32.0
fixed把选择框列固定在左边booleanfalse
getCheckboxProps选择框的默认属性配置(record: RecordType) => object
hidden是否隐藏选择列booleanfalse0.34.0
selectedRowKeys指定选中项的 key 数组,需要和 onChange 进行配合string[]
title自定义列表选择框标题string|ReactNode
width自定义列表选择框宽度string|number
onChange选中项发生变化时的回调。第一个参数会保存上次选中的 row keys,即使你做了分页受控或更新了 dataSource FAQ(selectedRowKeys: number[]|string[], selectedRows: RecordType[]) => void
onSelect用户手动点击某行选择框的回调(record: RecordType, selected: boolean, selectedRows: RecordType[], nativeEvent: MouseEvent) => void
onSelectAll用户手动点击表头选择框的回调,会选中/取消选中 dataSource 里的所有可选行(selected: boolean, selectedRows: RecordType[], changedRows: RecordType[]) => void

scroll

属性说明类型默认值版本
scrollToFirstRowOnChange当分页、排序、筛选变化后是否自动滚动到表格顶部booleanfalse1.1.0
x设置横向滚动区域的宽,可以为像素值、百分比或 'max-content'string|number
y设置纵向滚动区域的高,可以为像素值number

pagination

翻页组件配置。pagination 建议不要使用字面量写法。
属性说明类型默认值版本
currentPage当前页码number-
defaultCurrentPage默认的当前页码number1>=1.1.0
formatPageText翻页区域文案自定义格式化,传 false 关闭文案显示;该项影响表格翻页区域左侧文案显示,不同于 Pagination 组件的 showTotal 参数,请注意甄别。boolean | ({ currentStart: number, currentEnd: number, total: number }) => string|ReactNodetrue>=0.27.0
pageSize每页条数number10
position位置'bottom'|'top'|'both''bottom'
total数据总数number0>=0.25.0
其他配置详见Pagination

Resizable

resizable 对象型的参数,主要包括一些表格列伸缩时的事件方法。这些事件方法都可以返回一个对象,该对象会和最终的 column 合并。
属性说明类型默认值
onResize表格列改变宽度时触发(column: Column) => Column
onResizeStart表格列开始改变宽度时触发(column: Column) => Column
onResizeStop表格列停止改变宽度时触发(column: Column) => Column

方法

通过 ref 可以访问到 Table 提供的一些内部方法:
名称描述版本
getCurrentPageData()返回当前页的数据对象:{ dataSource: RecordType[], groups: Map<{groupKey: string, recordKeys: Set<string>}> }0.37.0

Accessibility

ARIA

  • 表格的 role 为 grid,树形表格的 role 为 treegrid
  • 行的 role 为 row,单元格的 role 为 gridcell
  • 表格新增了 aria-rowcount 和 aria-colcount 属性表示行和列的数量
  • 行新增了 aria-rowindex 表示当前属于第几行,第一行为 1
  • 树形表格的行具有 aria-level 表示当前行的树形层级,第一层为 1
  • 可展开表格行具有 aria-expanded 属性,表示当前行是否展开
  • 单元格的新增了 aria-colindex 表示当前格子属于第几列,第一列为 1
  • 列的筛选和排序按钮添加了 aria-label,行的选择按钮添加了 aria-label 属性

设计变量

FAQ

  • 表格数据为何没有更新?
    Table 组件目前所有参数都为浅层对比,也就是说如果该参数值类型为一个 Array 或者 Object,你需要手动改变其引用才能触发更新。同理,如果你不想触发额外更新,尽量不要直接在传参的时候使用字面量或是在 render 过程中定义引用型参数值:
    上述的写法在每次 render 时都会触发表格内部对数据的更新(会清空当前的选中行以及展开行 key 数组等)。为了性能及避免一些异常,请尽量将一些引用型参数定义在 render 方法之外(如果使用了 hooks 请利用 useMemo 或者 useState 进行存储)。
  • 为何我的表格行不能选中以及展开?
    请指定 rowKey 或者给 dataSource 的每项设置一个各不相同的 "key" 属性。表格内所有行相关的操作都需要使用到。
  • 如何实现点击排序按钮时自定义排序或传参给服务端排序?
    onChange 方法的入参包括 pagination、filters、sorter,用户可以根据 sorter 对 dataSource 进行自定义排序。
  • 如何给某一行添加 className?
    使用 onRow 或 onHeaderRow。
  • 如何给 table cell 设置样式?
    涉及到单个 cell 需要控制样式的,可以通过 column.onHeaderCell、column.onCell 控制。
  • 为何 rowSelection onChange 的第一个参数缓存了之前选中的 keys ?
    这么做为了在分页受控时,在第一页选中数据后,去第二页选择数据,回到第一页后选择的 row keys 丢失的场景。如果不想用缓存的 keys,可以从当前 dataSource 过滤一遍,或者使用 rowSelection onChange 的第二个参数。
  • Table 是如何实现的,我想了解更多细节?
    查看 Semi Table 组件设计方案了解更多。
查看更多 Table FAQ 和用例,点击 Table FAQ

© 2021 Semi Design. All rights reserved.

京ICP备19058139号-13浙公网安备 33011002016131号

Designed & Developed with love by Douyin FE & MED