虚拟化表格 beta
随着 Web 技术的不断发展,表格组件一直是 Web 应用中最受欢迎的组件之一,尤其是在仪表盘和数据分析场景中。对于表格 V1,即使只有 1000 条数据记录,由于性能不佳,使用起来也会非常烦人。
使用虚拟化表格,您可以在眨眼之间渲染大量数据。
提示
该组件仍在测试中,使用风险自负。如果您发现任何错误或问题,请在 GitHub 上报告给我们修复。此外,还有一些 API 在本文档中没有提及,其中一些尚未完全开发,因此在这里没有提及。
即使虚拟化表格效率很高,当数据负载过大时,您的网络和内存大小也可能成为应用的瓶颈。因此请记住,虚拟化表格绝不是万能的解决方案,请考虑对数据进行分页、添加筛选器等。
基础用法
让我们通过渲染一个包含 10 列和 1000 行的基本示例来演示虚拟化表格的性能。
自动调整尺寸
当您不想手动将 width 和 height 属性传递给表格时,您可以用 AutoResizer 包装表格组件。这将自动为您更新宽度和高度。
调整浏览器大小以查看其工作原理。
提示
请确保 AutoResizer 的父节点具有固定的高度,因为其默认高度值设置为 100%。或者,您可以通过将 style 属性传递给 AutoResizer 来定义它。
自定义单元格渲染器
当然,您可以根据需要渲染表格单元格。这里有一个如何自定义单元格的简单示例。
带选择功能的表格
使用自定义单元格渲染器为您的表格启用选择功能。
行内编辑
就像我们上面演示的选择功能一样,您可以使用相同的方法来启用行内编辑。
带状态的表格
您可以高亮显示您的表格内容,以区分“成功、信息、警告、危险”和其他状态。
要自定义行的外观,请使用 row-class-name 属性。例如,每第 10 行使用 bg-blue-200 类高亮显示,每第 5 行使用 bg-red-100 类高亮显示。
带固定行的表格
您可以让一些行固定在表格顶部,这可以通过使用 fixed-data 属性非常容易地实现。
您可以根据滚动事件动态设置固定行,如本例所示。
带固定列的表格
如果您出于某种原因希望列固定在左侧或右侧,可以通过向表格添加特殊属性来实现。
您可以将列的属性 fixed 设置为 true(表示 FixedDir.LEFT)、FixedDir.LEFT 或 FixedDir.RIGHT。
表头分组
通过自定义表头渲染器,您可以像本例中那样对表头进行分组。
提示
在这种情况下,我们使用了 JSX 功能,该功能在演练场中不受支持。您可以在本地环境或在线 IDE(如 codesandbox)中尝试它们。
建议您使用 JSX 编写表格组件,因为它包含 VNode 操作。
筛选
虚拟化表格提供了自定义表头渲染器,用于创建自定义表头。然后,我们可以利用这些来渲染筛选器。
可排序
您可以使用排序状态对表格进行排序。
受控排序
您可以根据需要定义多个可排序列。请记住,如果定义多个可排序列,UI 可能会让用户感到困惑,因为不清楚当前正在对哪一列进行排序。
交叉悬停
在处理大型列表时,很容易忘记当前正在访问的行和列。在这种情况下,使用此功能会非常有帮助。
列合并
虚拟化表格不使用内置的 table 元素,因此 colspan 和 rowspan 的行为与表格V1略有不同。但是,通过自定义行渲染器,这些功能仍然可以实现。在本节中,我们将演示如何实现这一点。
行合并
既然我们已经介绍了列合并,值得注意的是我们也有行合并。它与列合并有点不同,但思想基本相同。
行合并和列合并一起使用
我们可以将行合并和列合并结合起来,以满足您的业务目标!
树形数据
虚拟表格还可以以树形结构渲染数据。通过单击箭头图标,您可以展开或折叠树节点。
动态行高
虚拟表格能够渲染具有动态高度的行。如果您正在处理数据并且不确定内容大小,此功能非常适合渲染能够适应内容高度的行。要启用此功能,请传入 estimated-row-height 属性。估计高度与实际内容越接近,渲染体验就越流畅。
提示
每一行的高度在渲染行时动态测量。因此,如果您试图显示大量数据,UI 可能会跳动。
详情视图
使用动态高度渲染,您还可以在表格中显示详细视图。
自定义页脚
当您想显示总结性消息或信息时,渲染一个自定义页脚。
自定义空状态渲染器
渲染一个自定义的空元素。
遮罩层
当您想显示加载指示器或其他内容时,在表格上方渲染一个遮罩层。
手动滚动
使用 Table V2 提供的方法,通过所需的偏移量/行数进行手动/编程滚动。
提示
scrollToRow 的第二个参数是滚动策略,默认为 auto,它会自行计算滚动位置。如果您希望滚动到特定位置,可以自己定义策略。可用选项为 "auto" | "center" | "end" | "start" | "smart"
smart 和 auto 的区别在于 auto 是 smart 滚动策略的一个子集。
TableV2 API
TableV2 属性
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| cache | 提前渲染的行数,以提高性能 | number | 2 |
| estimated-row-height | 用于渲染动态高度行的估计行高 | number | — |
| header-class | 传递给表头包装器的自定义类名 | string / Function<HeaderClassGetter> | — |
| header-props | 传递给表头组件的自定义 props 名称 | object / Function<HeaderPropsGetter> | — |
| header-cell-props | 传递给表头单元格组件的自定义 props 名称 | object / Function<HeaderCellPropsGetter> | — |
| header-height | 表头的高度由 height 设置。如果给定一个数组,它将渲染等于其长度的表头行 | number/ number[] | 50 |
| footer-height | 页脚元素的高度,如果提供,将参与表格高度的计算。 | number | 0 |
| row-class | 传递给行包装器的自定义类名 | string / Function<RowClassGetter> | — |
| row-key | 每一行的键,如果未提供,将是行的索引 | string / Symbol / number | id |
| row-props | 传递给行组件的自定义 props 名称 | object / Function<RowPropsGetter> | — |
| row-height | 每一行的高度,用于计算表格的总高度 | number | 50 |
| row-event-handlers | 附加到每一行的处理程序集合 | object<RowEventHandlers> | — |
| cell-props | 传递给每个单元格(表头单元格除外)的额外 props | object / Function<CellPropsGetter> | — |
| columns | 列定义的数组。 | Column[] | — |
| data | 要在表格中渲染的数据数组。 | Data[] | [] |
| data-getter | 一个用于自定义从数据源获取数据的方法。 | Function<DataGetter<T>> | — |
| fixed-data | 用于在主内容上方和表头下方渲染行的数据 | object<Data> | — |
| expand-column-key | 指示哪一列是可展开的列键 | string | — |
| expanded-row-keys | 展开行的键数组,可与 v-model 一起使用 | KeyType[] | — |
| default-expanded-row-keys | 默认展开行的键数组,非响应式 | KeyType[] | — |
| class | 虚拟表格的类名,将应用于所有三个表格(左、右、主) | string / array / object | — |
| fixed | 指示表格列宽是固定的还是灵活的标志。 | boolean | false |
| width 必填 | 表格的宽度 | number | — |
| height 必填 | 表格的高度 | number | — |
| max-height | 表格的最大高度 | number | — |
| indent-size | 树形表格的水平缩进 | number | 12 |
| h-scrollbar-size | 指示表格的水平滚动条大小,用于防止水平和垂直滚动条重叠 | number | 6 |
| v-scrollbar-size | 指示表格的垂直滚动条大小,用于防止水平和垂直滚动条重叠 | number | 6 |
| scrollbar-always-on | 如果为 true,滚动条将始终显示,而不是在鼠标悬停在表格上时显示 | boolean | false |
| sort-by | 排序指示器 | object<SortBy> | {} |
| sort-state | 多重排序指示器 | object<SortState> | undefined |
TableV2 插槽
| 名称 | 类型 |
|---|---|
| cell | object<CellSlotProps> |
| header | object<HeaderSlotProps> |
| header-cell | object<HeaderCellSlotProps> |
| row | object<RowSlotProps> |
| footer | — |
| empty | — |
| overlay | — |
TableV2 事件
| 名称 | 描述 | 参数 |
|---|---|---|
| column-sort | 当列排序时调用 | object<ColumnSortParam> |
| expanded-rows-change | 当展开的行发生变化时调用 | KeyType[] |
| end-reached | 当到达表格末尾时调用。回调函数包含剩余距离,通常是滚动条的高度。 | Function |
| scroll | 滚动后调用 | object<ScrollParams> |
| rows-rendered | 当行被渲染时调用 | object<RowsRenderedParams> |
| row-expand | 当通过单击箭头图标展开/折叠树节点时调用 | object<RowExpandParams> |
TableV2 Exposes
| 方法 | 描述 | 参数 |
|---|---|---|
| scrollTo | 滚动到给定位置 | Function |
| scrollToLeft | 滚动到给定的水平位置 | Function |
| scrollToTop | 滚动到给定的垂直位置 | Function |
| scrollToRow | 使用指定的滚动策略滚动到给定的行 | Function |
提示
请注意,这些是 JavaScript 对象,因此您不能对这些属性使用 kebab-case(短横线命名法)
列属性
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| align | 表格单元格内容的对齐方式 | Alignment | left |
| class | 列的类名 | string | — |
| key | 唯一标识 | KeyType | — |
| dataKey | 数据的唯一标识 | KeyType | — |
| fixed | 列的固定方向 | boolean / FixedDir | false |
| flexGrow | CSSProperties 的 flex grow,仅在非固定表格时有用 | number | 0 |
| flexShrink | CSSProperties 的 flex shrink,仅在非固定表格时有用 | number | 1 |
| headerClass | 用于自定义表头列类 | string | — |
| hidden | 该列是否不可见 | boolean | — |
| style | 列单元格的自定义样式,将与网格单元格合并 | object | — |
| sortable | 指示该列是否可排序 | boolean | — |
| title | 在表头单元格中渲染的默认文本 | string | — |
| maxWidth | 列的最大宽度 | number | — |
| minWidth | 列的最小宽度 | number | — |
| width 必填 | 列的宽度 | number | — |
| cellRenderer | 自定义单元格渲染器 | VueComponent / (props: CellRenderProps) => VNode | — |
| headerCellRenderer | 自定义表头渲染器 | VueComponent / (props: HeaderRenderProps) => VNode | — |
类型定义
显示类型声明
type HeaderClassGetter = (param: {
columns: Column<any>[]
headerIndex: number
}) => string
type HeaderPropsGetter = (param: {
columns: Column<any>[]
headerIndex: number
}) => Record<string, any>
type HeaderCellPropsGetter = (param: {
columns: Column<any>[]
column: Column<any>
columnIndex: number
headerIndex: number
style: CSSProperties
}) => Record<string, any>
type RowClassGetter = (param: {
columns: Column<any>[]
rowData: any
rowIndex: number
}) => string
type RowPropsGetter = (param: {
columns: Column<any>[]
rowData: any
rowIndex: number
}) => Record<string, any>
type CellPropsGetter = (param: {
column: Column<any>
columns: Column<any>[]
columnIndex: number
cellData: any
rowData: any
rowIndex: number
}) => void
type DataGetterParams<T> = {
columns: Column<T>[]
column: Column<T>
columnIndex: number
} & RowCommonParams
type DataGetter<T> = (params: DataGetterParams<T>) => T
type CellRenderProps<T> = {
cellData: T
column: Column<T>
columns: Column<T>[]
columnIndex: number
rowData: any
rowIndex: number
}
type HeaderRenderProps<T> = {
column: Column<T>
columns: Column<T>[]
columnIndex: number
headerIndex: number
}
type ScrollParams = {
xAxisScrollDir: 'forward' | 'backward'
scrollLeft: number
yAxisScrollDir: 'forward' | 'backward'
scrollTop: number
}
type CellSlotProps<T> = {
column: Column<T>
columns: Column<T>[]
columnIndex: number
depth: number
style: CSSProperties
rowData: any
rowIndex: number
isScrolling: boolean
expandIconProps?:
| {
rowData: any
rowIndex: number
onExpand: (expand: boolean) => void
}
| undefined
}
type HeaderSlotProps = {
cells: VNode[]
columns: Column<any>[]
headerIndex: number
}
type HeaderCellSlotProps = {
class: string
columns: Column<any>[]
column: Column<any>
columnIndex: number
headerIndex: number
style: CSSProperties
headerCellProps?: any
sortBy: SortBy
sortState?: SortState | undefined
onColumnSorted: (e: MouseEvent) => void
}
type RowCommonParams = {
rowData: any
rowIndex: number
}
type RowEventHandlerParams = {
rowKey: KeyType
event: Event
} & RowCommonParams
type RowEventHandler = (params: RowEventHandlerParams) => void
type RowEventHandlers = {
onClick?: RowEventHandler
onContextmenu?: RowEventHandler
onDblclick?: RowEventHandler
onMouseenter?: RowEventHandler
onMouseleave?: RowEventHandler
}
type RowsRenderedParams = {
rowCacheStart: number
rowCacheEnd: number
rowVisibleStart: number
rowVisibleEnd: number
}
type RowSlotProps = {
columns: Column<any>[]
rowData: any
columnIndex: number
rowIndex: number
data: any
key: number | string
isScrolling?: boolean
style: CSSProperties
}
type RowExpandParams = {
expanded: boolean
rowKey: KeyType
} & RowCommonParams
type Data = {
[key: KeyType]: any
children?: Array<any>
}
type FixedData = Data
type KeyType = string | number | symbol
type ColumnSortParam<T> = { column: Column<T>; key: KeyType; order: SortOrder }
enum SortOrder {
ASC = 'asc',
DESC = 'desc',
}
enum Alignment {
LEFT = 'left',
CENTER = 'center',
RIGHT = 'right',
}
type SortBy = { key: KeyType; Order: SortOrder }
type SortState = Record<KeyType, SortOrder>常见问题
如何在第一列渲染一个带复选框的列表?
由于您可以定义自己的单元格渲染器,您可以像自定义单元格渲染器示例那样自己渲染 checkbox,并自行维护其状态。
为什么虚拟化表格提供的功能比 TableV1 少?
对于虚拟化表格,我们打算提供较少的功能,让用户根据需要实现自己的功能。集成太多功能会使代码难以维护,而且对于大多数用户来说,基本功能已经足够了。一些关键功能尚未开发。我们很乐意听取您的意见。加入 Discord 保持关注。