如何使用

往 Table 传入表头 columns 和数据 dataSource 进行渲染。

注意事项
请为 `dataSource` 中的每个数据项提供一个与其他数据项值不同的 `key`,或者使用 `rowKey` 参数指定一个作为主键的属性名,表格的行选择、展开等绝大多数行操作功能都会使用到。
jsx

import { Table } from '@kousum/semi-ui-vue';

function App() {
    const columns = [
        {
            title: '标题',
            dataIndex: 'name',
        },
        {
            title: '大小',
            dataIndex: 'size',
        },
        {
            title: '所有者',
            dataIndex: 'owner',
        },
        {
            title: '更新日期',
            dataIndex: 'updateTime',
        },
    ];
    const data = [
        {
            key: '1',
            name: 'Semi Design 设计稿.fig',
            nameIconSrc: 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/figma-icon.png',
            size: '2M',
            owner: '姜鹏志',
            status: 'success',
            updateTime: '2020-02-02 05:13',
            avatarBg: 'grey',
        },
        {
            key: '2',
            name: 'Semi Design 分享演示文稿',
            nameIconSrc: 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/docs-icon.png',
            size: '2M',
            owner: '郝宣',
            status: 'pending',
            updateTime: '2020-01-17 05:31',
            avatarBg: 'red',
        },
        {
            key: '3',
            name: '设计文档',
            nameIconSrc: 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/docs-icon.png',
            size: '34KB',
            status: 'wait',
            owner: 'Zoey Edwards',
            updateTime: '2020-01-26 11:01',
            avatarBg: 'light-blue',
        },
    ];

    return <Table columns={columns} dataSource={data} pagination={false} />;
}

export default App

代码演示

基本表格

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

JSX 写法

你也可以使用 JSX 语法定义 columns,注意 Table 仅支持 columns 的 JSX 语法定义。你不能够使用任何组件包裹 Table.Column 组件。

注意事项
1. JSX 写法的表格暂时不支持 resizable 功能;
2. 使用 JSX 写法时,请不要与配置写法同时使用;如果同时使用,仅配置写法生效,不会进行聚合操作。

行选择操作

往 Table 传入 rowSelection 即可打开此功能。

  • 点击表头的选择框,会选择 dataSource 里所有不是 disabled 状态的行。选择所有行回调函数为 onSelectAll
  • 点击行的选择框会选中当前行。它的回调函数为 onSelect
注意事项
1. 请务必为 `dataSource` 中每行数据提供一个与其他行值不同的 `key`,或者使用 `rowKey` 参数指定一个作为主键的属性名。
2. 如你遇见在第二页点击行选择后,回到第一页问题,请检查组件渲染是否触发了 `dataSource` 更新(浅对比)。`dataSource` 更新后,非受控的翻页器会回到第一页。请将 `dataSource` 放在 state 内。

自定义渲染

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

带分页组件的表格

表格分页目前支持两种模式:受控和非受控模式。

  • 受控模式下,分页的状态完全由外部传入,依据为是否往 Table 传入了 pagination.currentPage 这个字段。一般情况下,受控模式适用于远程拉取数据并渲染。
  • 非受控模式下,Table 默认会将传入的 dataSource 长度作为 total 传给 Pagination 组件,当然你也可以传入一个 total 字段来覆盖 Table 组件的取值,不过我们并不推荐用户在非受控分页模式下传入这个字段。

拉取远程数据

正常情况下,数据往往不是一次性获取的,我们会在点击页码、过滤器或者排序按钮时从接口重新获取数据,这种情况下请使用受控模式来处理分页。用户需往 Table 传入 pagination.currentPage 这个字段,此时分页组件的渲染完全依赖于传入的 pagination 对象。

注意事项
1. 非受控时,pagination 如果是对象类型则不推荐使用字面量写法,原因是字面量写法会导致表格渲染至初始状态(看起来像是分页器没有生效)。请尽量将引用型参数定义在 render 方法之外,如果使用了 hooks 请利用 useMemo 或 useState 进行存储;
2. 受控模式下,Table 不会对 dataSource 分页,请给 dataSource 传入当前页数据

固定列或表头

可以通过设置 column 的 fixed 属性以及 scroll.x 来进行列固定,通过设置 scroll.y 来进行表头固定。

如果是固定值,设置为 >=所有固定列宽之和+所有表格列宽之和 的数值。

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

通过 sticky 属性可以将表头固定在页面顶部。v2.21 版本支持。传入 top 时可以控制距离滚动容器的距离。

jsx

import { Table, Avatar } from '@kousum/semi-ui-vue';
import { IconMore } from '@kousum/semi-icons-vue';
import * as dateFns from 'date-fns';

const DAY = 24 * 60 * 60 * 1000;
const figmaIconUrl = 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ptlz_zlp/ljhwZthlaukjlkulzlp/figma-icon.png';

const columns = [
    {
        title: '标题',
        dataIndex: 'name',
        fixed: true,
        width: 250,
        render: (text, record, index) => {
            return (
                <div>
                    <Avatar size="small" shape="square" src={figmaIconUrl} style={{ marginRight: '12px' }}></Avatar>
                    {text}
                </div>
            );
        },
        filters: [
            {
                text: 'Semi Design 设计稿',
                value: 'Semi Design 设计稿',
            },
            {
                text: 'Semi D2C 设计稿',
                value: 'Semi D2C 设计稿',
            },
        ],
        onFilter: (value, record) => record.name.includes(value),
    },
    {
        title: '大小',
        dataIndex: 'size',
        width: 200,
        sorter: (a, b) => (a.size - b.size > 0 ? 1 : -1),
        render: text => `${text} KB`,
    },
    {
        title: '所有者',
        dataIndex: 'owner',
        width: 200,
        render: (text, record, index) => {
            return (
                <div>
                    <Avatar size="small" color={record.avatarBg} style={{ marginRight: 4 }}>
                        {typeof text === 'string' && text.slice(0, 1)}
                    </Avatar>
                    {text}
                </div>
            );
        },
    },
    {
        title: '更新日期',
        dataIndex: 'updateTime',
        width: 200,
        sorter: (a, b) => (a.updateTime - b.updateTime > 0 ? 1 : -1),
        render: value => {
            return dateFns.format(new Date(value), 'yyyy-MM-dd');
        },
    },
    {
        title: '',
        dataIndex: 'operate',
        fixed: 'right',
        align: 'center',
        width: 100,
        render: () => {
            return <IconMore />;
        },
    },
];

function App() {
    const [dataSource, setData] = useState([]);

    const scroll = useMemo(() => ({ y: 300, x: 1200 }), []);
    const rowSelection = useMemo(
        () => ({
            onChange: (selectedRowKeys, selectedRows) => {
                console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
            },
            getCheckboxProps: record => ({
                disabled: record.name === 'Michael James', // Column configuration not to be checked
                name: record.name,
            }),
            fixed: true,
        }),
        []
    );

    const getData = () => {
        const data = [];
        for (let i = 0; i < 46; i++) {
            const isSemiDesign = i % 2 === 0;
            const randomNumber = (i * 1000) % 199;
            data.push({
                key: '' + i,
                name: isSemiDesign ? `Semi Design 设计稿${i}.fig` : `Semi D2C 设计稿${i}.fig`,
                owner: isSemiDesign ? '姜鹏志' : '郝宣',
                size: randomNumber,
                updateTime: new Date().valueOf() + randomNumber * DAY,
                avatarBg: isSemiDesign ? 'grey' : 'red',
            });
        }
        return data;
    };

    useEffect(() => {
        const data = getData();
        setData(data);
    }, []);

    return (
        <Table
            sticky={{ top: 60 }}
            columns={columns}
            dataSource={dataSource}
            rowSelection={rowSelection}
            scroll={scroll}
        />
    );
}

render(App);

带排序和过滤功能的表头

表格内部集成了过滤器和排序控件,用户可以通过在 Column 中传入 filters 以及 onFilter 开启表头的过滤器控件展示,传入 sorter 开启表头的排序控件的展示。

注意事项
1. 请为 `dataSource` 中的每个数据项提供一个与其他数据项值不同的 `key`,或者使用 `rowKey` 参数指定一个作为主键的属性名,表格的行选择、展开等绝大多数行操作功能都会使用到。
2. 排序和筛选列必须设置独立的 `dataIndex`

sorter 为函数类型时,可以通过函数的第三个参数获取 sortOrder 状态。函数类型为 (a?: RecordType, b?: RecordType, sortOrder?: 'ascend' | 'descend') => number。v2.47 版本支持。

可通过 showSortTip 属性控制是否展示排序提示,自 v2.65 版本支持,默认为 false。当开启提示后,当仅有排序功能时候,鼠标移动至表头时,会展示排序提示;其他情况下,仅鼠标移动至排序图标时,会展示排序提示。

:在使用 sortOrder 属性受控排序时,由于无法预测下一个排序顺序,因此 showSortTip 不生效,不会展示提示。

自定义表头筛选

如果你需要将筛选器输入框展示在表头,可在 title 传入 ReactNode,配合 filteredValue 使用。

自定义筛选器

使用 renderFilterDropdown 自定义渲染筛选器面板。v2.52 支持。

你可以在用户输入筛选值的时候调用 setTempFilteredValue 存储筛选值,在筛选值输入完毕后调用 confirm 触发真正的筛选。也可以通过 confirm({ filteredValue }) 直接筛选。

设置 tempFilteredValue 的原因是在需要存储临时筛选值的场景,不需要自己声明一个 state 保存这个临时筛选值。

typescript
type RenderFilterDropdown = (props?: RenderFilterDropdownProps) => React.ReactNode;
interface RenderFilterDropdownProps {
    /** 临时筛选值,初始值为 `filteredValue` 或 `defaultFilteredValue`  */
    tempFilteredValue: any[];
    /** 设置临时筛选值  */
    setTempFilteredValue: (tempFilteredValue: any[]) => void;
    /** `confirm` 默认会将 `tempFilteredValue` 赋值给 `filteredValue` 并触发 `onChange` 事件。你也可以通过传入 `filteredValue` 直接设置筛选值  */
    confirm: (props?: { closeDropdown?: boolean; filteredValue?: any[] }) => void;
    /** 清除筛选值、临时筛选值  */
    clear: (props?: { closeDropdown?: boolean }) => void;
    /** 关闭 dropdown  */
    close: () => void;
    /** 筛选器配置项,如不需要可以不传  */
    filters?: RenderDropdownProps['filters']
}

自定义筛选项渲染

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 给每列设置一个背景色实现相同效果。

单元格缩略

使用 ellipsis 可以让单元格自动实现缩略效果。v2.34.0 支持。

设置 ellipsis.showTitle 为 false 可以隐藏默认原生的 HTML title。 配合 column.render 可以自定义内容提示。

可伸缩列

版本 >= 0.15.0

基本伸缩列

对于一些内容比较多的列,可以选择打开伸缩列功能,在表头进行拉拽实现列宽的实时变化。

不过你需要注意一些参数:

  • resizable 设定为 true 或者一个 object
  • columns 里需要伸缩功能的列都要指定 width 这个字段(如果不传,该列不具备伸缩功能,且其列宽度会被浏览器自动调整)
  • column.resize 可以在 resizable 开启后生效,设置为 false 后,列不再支持伸缩。v2.42 支持

与固定列同时使用时,需指定某一列不设置宽度

不推荐与 scroll.x 同时使用,scroll.x 指定表格是有宽度范围的,而伸缩列会拓展列宽,这可能会导致表格对不齐

进阶的伸缩列

resizable 还能为一个 Object,包括三个事件方法:

  • onResize
  • onResizeStart
  • onResizeStop

分别触发于列宽改变中开始改变结束改变三个时机。开发者可以选择在这个时机修改 column,例如在拉拽时增加一个拖动时的竖线效果等,如下例。

本例中使用的 CSS 样式定义:

css
#components-table-demo-resizable-column .my-resizing {
    border-right: 2px solid red;
}

#components-table-demo-resizable-column .react-resizable-handle:hover {
    background-color: red;
}

#components-table-demo-resizable-column .my-resizing:hover .react-resizable-handle {
    background-color: inherit;
}

拖拽排序

使用 dnd-kit 搭配 components API 可轻松实现拖拽排序。v2.58 版本支持。

表格分组

版本:>=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 接受的入参为:

text
{
    filter: ReactNode, // 筛选按钮
    sorter: ReactNode, // 排序按钮
    selection: ReactNode, // 选择按钮
}

Column.render 第四个入参为一个 object,结构如下:

text
{
    expandIcon: ReactNode, // 展开按钮
    selection: ReactNode, // 选择按钮
    indentTex: ReactNode, // 缩进
}

下方的例子则是将复选框与内容渲染至同一单元格和表头中。

表头合并

版本:>=1.1.0

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

合并表头配置式写法

合并表头 JSX 写法

行列合并

  • 表头除了通过 children 写法进行合并外,可通过设置 column.colSpan 进行表头的列合并。
  • 表格支持行/列合并,使用 render 里的单元格属性 colSpan 或者 rowSpan 设值为 0 时,设置的表格不会渲染。
text
type Render = (text: string, record: Object, index: number, options?: RenderOptions) => {
    children: React.ReactNode;
    props: {
        colSpan?: number,
        rowSpan?: number,
    },
    [x: string]: any;
}

interface RenderOptions {
    expandIcon?: React.ReactNode;
}

API 参考

Table

属性说明类型默认值版本
bordered是否展示外边框和列边框booleanfalse
childrenRecordName树形表格 dataSource 中每行元素中表示子级数据的字段,默认为 childrenstring'children'
className最外层样式名string
clickGroupedRowToExpand点击分组表头行时分组内容展开或收起boolean0.29.0
columns表格列的配置描述,详见ColumnColumn[][]
components覆盖 Table 的组成元素,如 table, body,row,td,th 等TableComponents
dataSource数据。请为每一条数据分配一个独立的 key,或使用 rowKey 指定一个作为主键的属性名RecordType[][]
defaultExpandAllRows默认是否展开所有行,动态加载数据时不生效booleanfalse
defaultExpandAllGroupRows默认是否展开分组行,动态加载数据时不生效booleanfalse1.30.0
defaultExpandedRowKeys默认展开的行 key 数组,,动态加载数据时不生效Array<*>[]
directionRTL、LTR 方向,默认值等于 ConfigProvider direction,可在此单独配置 Table 的 direction'ltr' | 'rtl'2.31.0
empty无数据时展示的内容ReactNode'暂无数据'
expandCellFixed展开图标所在列是否固定,与 Column 中的 fixed 取值相同boolean|stringfalse
expandIcon自定义展开按钮,传 false 关闭默认的渲染boolean | ReactNode
| (expanded: boolean) => ReactNode
expandedRowKeys展开的行,传入此参数时行展开功能将受控(string | number)[]
expandedRowRender额外的展开行。请为每一条数据分配一个独立的 key,或使用 rowKey 指定一个作为主键的属性名(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
keepDOM折叠行时是否不销毁被折叠的 DOMbooleanfalse
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
sticky固定表头boolean |false2.21.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

一些上面用到的类型定义:

typescript
// PaginationProps 为 Pagination 组件支持的 props
interface TablePaginationProps extends PaginationProps {
    position?: PaginationPosition;
    formatPageText?: FormatPageText;
}

type VirtualizedItemSizeFn = (index?: number) => number;
type VirtualizedOnScrollArgs = {
    scrollDirection?: 'forward' | 'backward';
    scrollOffset?: number;
    scrollUpdateWasRequested?: boolean;
};
type VirtualizedOnScroll = (object: VirtualizedOnScrollArgs) => void;

type Virtualized =
    | boolean
    | {
          itemSize?: number | VirtualizedItemSizeFn;
          onScroll?: VirtualizedOnScroll;
      };

RecordType 为 Table 和 Column 的泛型参数,默认为 object 类型。你可以这样使用 RecordType:

typescript
import { ColumnProps } from 'table/interface';

interface Record {
    title?: string;
    dataIndex?: string;
    width?: number;
    render?: Function;
    key?: string;
    name?: string;
    age?: number;
    address?: string;
}

function App() {
    const columns: ColumnProps<Record>[] = [
            {
                title: 'Name',
                dataIndex: 'name',
                width: 200,
            },
            // ...
    ];

    const data: Record[] = [
        {
            key: '1',
            name: 'John Brown',
            age: 32,
            address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
        },
        // ...
    ];

    return (
        <Table<Record>
            columns={columns}
            dataSource={data}
            // ...
        >
    );
}

onHeaderRow / onRow 用法

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

jsx

import { Table } from '@kousum/semi-ui-vue';

() => (
    <Table
        onRow={(record, index) => {
            return {
                onClick: event => {}, // 点击行
                onMouseEnter: event => {}, // 鼠标移入行
                onMouseLeave: event => {}, // 鼠标移出行
                className: '',
                // ...
                // 其他可以作用于 tr 的属性或事件
            };
        }}
        onHeaderRow={(columns, index) => {
            return {
                onClick: event => {}, // 点击表头行
                onMouseEnter: event => {}, // 鼠标移入表头行
                onMouseLeave: event => {}, // 鼠标移出表头行
                className: '',
                // ...
                // 其他可以作用于 th 的属性或事件
            };
        }}
    />
);

Column

属性说明类型默认值版本
align设置列的对齐方式,在 RTL 时会自动切换'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
ellipsis文本缩略,开启后 table-layout 会自动切换为 fixedboolean|false2.34.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',在 RTL 时会自动切换boolean|stringfalse
keyReact 需要的 key,如果已经设置了唯一的 dataIndex,可以忽略这个属性string
render生成复杂数据的渲染函数,参数分别为当前行的值,当前行数据,行索引,@return 里面可以设置表格行/列合并(text: any, record: RecordType, index: number, { expandIcon?: ReactNode, selection?: ReactNode, indentText?: ReactNode }) => object|ReactNode
renderFilterDropdown自定义筛选器 dropdown 面板,用法详见自定义筛选器(props?: RenderFilterDropdownProps) => React.ReactNode;-2.52.0
renderFilterDropdownItem自定义每个筛选项渲染方式,用法详见自定义筛选项渲染({ value: any, text: any, onChange: Function, level: number, ...otherProps }) => ReactNode-1.1.0
resize是否开启 resize 模式,只有 Table resizable 开启后此属性才会生效boolean2.42.0
showSortTip是否展示排序提示, 如果设置了 sortOrder,排序受控,则该参数不会生效booleanfalse2.65.0
sortChildrenRecord是否对子级数据进行本地排序boolean0.29.0
sortOrder排序的受控属性,外界可用此控制列的排序,可设置为 'ascend'|'descend'|falseboolean| stringfalse
sorter排序函数,本地排序使用一个函数(参考 Array.sort 的 compareFunction),需要服务端排序可设为 true。必须给排序列设置一个独立的 dataIndex,必须为 dataSource 里面的每条数据项设置独立的 keyboolean|(r1: RecordType, r2: RecordType, sortOrder: 'ascend' | 'descend') => numbertrue
sortIcon自定义 sort 图标,返回的节点控制了整个排序按钮,包含升序和降序。需根据 sortOrder 控制高亮行为(props: { sortOrder }) => ReactNode2.50.0
title列头显示文字。传入 function 时,title 将使用函数的返回值;传入其他类型,将会和 sorter、filter 进行聚合。需要搭配 useFullRender 获取函数类型中的 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本地模式下,确定筛选的运行函数。必须给筛选列设置一个独立的 dataIndex,必须为 dataSource 里面的每条数据项设置独立的 key(filteredValue: any, record: RecordType) => boolean
onFilterDropdownVisibleChange自定义筛选菜单可见变化时回调(visible: boolean) => void
onHeaderCell设置头部单元格属性(column: RecordType, columnIndex: number) => object

一些上面用到的类型定义:

typescript
type Filter = {
    value: any;
    text: React.ReactNode;
    children?: Filter[];
};

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
renderCell自定义渲染勾选框({ selected: boolean, record: RecordType, originNode: JSX.Element, inHeader: boolean, disabled: boolean, indeterminate: boolean, index?: number, selectRow?: (selected: boolean, e: Event) => void, selectAll?: (selected: boolean, e: Event) => void }) => ReactNode2.52.0
selectedRowKeys指定选中项的 key 数组,需要和 onChange 进行配合string[]
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 建议不要使用字面量写法。

注意:pagination.onChange 设置后,Table onChange 不再响应分页器变化。

属性说明类型默认值版本
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 提供的一些内部方法:

jsx

import { Table } from '@kousum/semi-ui-vue';

function Demo() {
    const ref = useRef();

    useEffect(() => {
        ref.getCurrentPageData(); // => { dataSource: [/*...*/], groups: /*...*/ }
    }, []);

    return (
        <Table
            columns={
                [
                    /*...*/
                ]
            }
            dataSource={
                [
                    /*...*/
                ]
            }
            ref={ref}
        />
    );
}
名称描述版本
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 属性

RTL/LTR

文案规范

  • 表格标题
    • 表格标题应清晰的让用户感知到表格的目的;
    • 为复杂表格添加描述,为用户提供更多关于表格的上下文信息;
    • 使用句子大小写;
  • 列标题
    • 保持列标题简洁,建议使用 1-2 个词作为列标题;
    • 当列标题较长时,建议 2 行显示,剩余文字缩略并在 Tooltip 中显示完全;
    • 采用 Sentence case 的大小写规则;
    • 列标题使用句子大小写;
  • 表格操作

设计变量

FAQ

  • 点击第二页的行选择按钮,会跳转到第一页?

    Table 的 dataSource 更新后,会将页码重置到初始态。请检查数据源是否在组件渲染时发生了变化。

    typescript
    function App() {
        const [dataSource, setDataSource] = useState([]);
    
        useEffect(() => {
            // ✅ 正确
            const getData = () => {
                // fetch data
                const newData = fetch(/**/);
                // set data
                setDataSource(dataSource);
            };
    
            getData();
        }, []);
    
        // ❌ 错误
        const data = [];
    
        return <Table dataSource={data} columns={[/*...*/]} />;
    }
  • 筛选后的数据条数不对?

    请检查你的筛选列和数据源是否配置正确。

    筛选列需设置独立的 dataIndex,同时 dataSource 需要设置独立的 key,请参考 dataSource API。否则筛选功能无法正常工作。

  • 表格数据为何没有更新?

    Table 组件目前所有参数都为浅层对比,也就是说如果该参数值类型为一个 Array 或者 Object,你需要手动改变其引用才能触发更新。同理,如果你不想触发额外更新,尽量不要直接在传参的时候使用字面量或是在 render 过程中定义引用型参数值:

    text
    // ...render() {
        <Table dataSource={[/*...*/]} columns={[/*...*/]} />}

    上述的写法在每次 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 暂不支持单行选则功能,用户可以通过自定义方式实现单选。实现方式移步 Table FAQ 文档。

  • Table 是如何实现的,我想了解更多细节?

    查看 Semi Table 组件设计方案了解更多。

查看更多 Table FAQ 和用例,点击 Table FAQ