交叉表
交叉表是一个比较底层的 React 组件,仅提供相应表格结构的渲染能力。注意交叉表...
- 没有 透视能力
- 没有 收拢展开功能
#
主要特性- 不依赖特定组件库,可独立使用
- 简单、一致的 API 与渲染模型:
左树 + 上树 => 表格
- 高性能:数据量较大时,自动开启虚拟滚动
#
基本用法在简单的场景下,交叉表的用法很简单:
- 通过
leftTree
描述表格左侧的树状结构; - 通过
topTree
描述表格上方的树状结构; - 通过
getValue
/render
来定义每个单元格的内容; - 交叉表组件会根据 leftTree/topTree 来渲染表格结构,并调用
getValue
/render
渲染单元格的内容
<CrossTable // 推荐为交叉表设置一个默认列宽 defaultColumnWidth={100} leftTree={leftTree} topTree={topTree} getValue={(leftNode, topNode) => { // 可选的自定义的取数逻辑,针对每个单元格都会调用一次 // leftNode 表示当前单元格对应的左侧树节点,topNode 是对应的上方树节点 }} render={(value, leftNode, topNode) => { // 可选的 自定义的渲染逻辑 return value }}/>
2021年 养猪计划
#
leftTree 的结构交叉表左侧的树(leftTree)是一个树节点的数组,每个树节点的结构如下:
/** 交叉表左侧或上方的树节点基类 */interface CrossTreeNode { key: string value: string title?: ReactNode data?: any hidden?: boolean children?: CrossTreeNode[]}
/** 交叉表左侧树状结构的树节点 */interface LeftCrossTreeNode extends CrossTreeNode { children?: CrossTreeNode[]}
- 主要属性:
key
用于在树中唯一标记一个节点;value
表示节点中的文本值;children
为子节点数组;
- 可选属性:
title
若非空,被渲染在页面中时,节点内容将由 title 提供- 在不是页面渲染的情况下(例如导出到文件),title 将被忽略
hidden
表示是否隐藏节点data
为附加在节点上的数据data
中可以放任何内容- 放在节点中的数据,可在渲染单元格时取出,用于决定渲染结果
#
topTree 的结构topTree 的结构与 leftTree 类似,但其树节点的配置较为丰富,结构如下:
/** 交叉表上方树状结构的树节点 * 列的名称现由 value 字段提供,故从 ArtColumnStaticPart 移除了 name 字段 */interface TopCrossTreeNode extends CrossTreeNode, Omit<ArtColumnStaticPart, 'name'> { children?: TopCrossTreeNode[]}
上方的树节点继承(extends)了左侧树节点的结构,拥有相同的 key/value/data/title/hidden/children 字段。
交叉表底层使用了 BaseTable
进行渲染,而 BaseTable
中主要的表格配置是放在每一列之上的。在 topTree 中,每个叶子节点都对应的了表格中的一列,所以每个节点除了包含 key/value/data/children 之外,还包含了部分列配置(即 ArtColumnStaticPart
)。ArtColumnStaticPart
的结构如下:
name
列的名称;注意因为树节点已经含有 value 字段,故 name 字段在 TopCrossTreeNode 中是不起作用的)code
在数据中的字段 code;注意交叉表使用自定义的 getValue/render 进行取值或渲染,会屏蔽掉 code 的默认取值方式title
列标题,如果该字段非空,在渲染时会覆盖 value 字段width
列的宽度align
单元格中的文本或内容的 对其方向hidden
是否隐藏;不推荐为交叉表的数据列设置隐藏lock
是否锁列;不推荐为交叉表的数据列设置锁列headerCellProps
表头单元格的 propsfeatures
功能开关
#
其他 props交叉表的底层依赖了 BaseTable
,故两者的 props 大部分是相同的。两者的不同点具体如下:
- 交叉表没有 dataSource 和 columns
- 表格结构由 leftTree 和 rightTree 提供,而单元格内容由 getValue 提供
- 单元格渲染内容可使用 render 进行自定义;单元格的 props(即表格内的 td 元素)可使用 getCellProps 进行自定义
- 交叉表没有 primaryKey
- 交叉表左侧树中每个节点都有一个唯一的 key 值,故不再需要上层指定 primaryKey
- 其他新增的 props
- 交叉表使用 leftMetaColumns 来描述 leftTree 所处的列的配置
- 交叉表渲染时,左侧的树会占据表格的前几列,并自动设置 lock=true,leftMetaColumns 可用于自定义这些列
- leftTotalNode:当 leftTree 为空时,leftTotalNode 用于渲染「总计行」,避免表格中没有数据行
- topTotalNode:当 topTree 为空时,topTotalNode 用于渲染「总计列」,避免表格中没有数据列
- 交叉表使用 leftMetaColumns 来描述 leftTree 所处的列的配置
交叉表的 props 具体如下:
interface CrossTableProps extends Omit<BaseTableProps, 'dataSource' | 'columns' | 'primaryKey'> { leftTree: LeftCrossTreeNode[] topTree: TopCrossTreeNode[] leftMetaColumns?: CrossTableLeftMetaColumn[] leftTotalNode?: LeftCrossTreeNode topTotalNode?: TopCrossTreeNode
getValue(leftNode: LeftCrossTreeNode, topNode: TopCrossTreeNode, leftDepth: number, topDepth: number): any
render?( value: any, leftNode: LeftCrossTreeNode, topNode: TopCrossTreeNode, leftDepth: number, topDepth: number, ): ReactNode
getCellProps?( value: any, leftNode: LeftCrossTreeNode, topNode: TopCrossTreeNode, leftDepth: number, topDepth: number, ): CellProps}
export interface CrossTableLeftMetaColumn extends Omit<ArtColumnStaticPart, 'hidden'> { /** 自定义渲染方法 */ render?(leftNode: LeftCrossTreeNode, leftDepth: number): ReactNode
/** 自定义的获取单元格 props 的方法 */ getCellProps?(leftNode: LeftCrossTreeNode, leftDepth: number): CellProps}
不要被长长的 TypeScript 类型代码吓到,交叉表的 props 其实和 BaseTable 差别不大。
#
复杂场景下的交叉表交叉表的左树/上树的结构被设计为 { key, value, children }
的简单结构,方便上层调用者能够从不同的数据源中生成 leftTree/topTree。
在复杂场景下,需要上层根据业务需求手动生成 leftTree/topTree/getValue。ali-react-table 也提供了一定的透视能力,可在交叉表的基础上实现前端聚合的透视表,可供使用和参考。
例如,对 leftTree 进行如下处理,可以关闭左侧自动单元格合并功能:
// 注意这个时候每个节点的 key 都要不同const leftTree = [ { key: 'forenoon-9', value: '上午', children: [{ key: '9', value: '9:00-10:00' }] }, { key: 'forenoon-10', value: '上午', children: [{ key: '10', value: '10:00-11:00' }] }, { key: 'forenoon-11', value: '上午', children: [{ key: '11', value: '11:00-12:00' }] }, // other nodes...]
2021年 养猪计划
#
交叉表定制交叉表的底层仍是 <BaseTable />
。
对交叉表进行定制时,可以先通过 buildCrossTable
根据交叉表的输入生成 dataSource / columns,进行一些自定义的处理,然后再将处理好的数据传给 BaseTable,并注意为 BaseTable 设置 primaryKey={ROW_KEY}
。
可以使用 pipeline 进行表格功能拓展(具体可以参考这个示例),但因为交叉表本身很复杂,只有一部分比较简单的 pipeline feature 可以和交叉表一起工作,例如 列范围高亮.
import { BaseTable } from 'ali-react-table'import { buildCrossTable, ROW_KEY } from 'ali-react-table/pivot'
function MyComplexTable() { // 将「传给 CrossTable 的参数」传给 buildCrossTable const { dataSource, columns } = buildCrossTable({ leftTree, topTree, getValue, // 这里也支持其他的 CrossTable 的 props: // leftTotalNode, topTotalNode, leftMetaColumns, render, getCellProps })
// 在这里可以对 dataSource 和 columns 进行一定的处理后,再将数据传递给 BaseTable
return ( <BaseTable className="my-complex-table" primaryKey={ROW_KEY} defaultColumnWidth={100} dataSource={dataSource} columns={columns} /> )}
columnOffset
与 rowOffset
#
danger
columnOffset
与 rowOffset
仍是一个实验性的 API,可能在将来会发生变更.
交叉表的左侧部分自带了单元格合并功能,而单元格合并功能依赖于 rowIndex/colIndex,所以在处理 dataSource/columns 的过程中需要注意左侧部分的整体位置发生了变化(例如在表格左侧多了一列用于展示每一行的序号).
如果左侧部分整体位置将发生变化,在调用 buildCrossTable(...)
时就需要设置相应的 options.rowOffset
/ options.columnOffset
来声明最终交叉表部分的行列偏移量。
在下面的这个示例中,我们在交叉表的左侧新增了两列(多选一列、序号一列),在调用时的代码为 buildCrossTable({ columnOffset:2 })
。