news 2026/10/7 2:10:23

rsuite 树形表格(Tree Table)完全指南:层级数据的展示、展开控制与虚拟化实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
rsuite 树形表格(Tree Table)完全指南:层级数据的展示、展开控制与虚拟化实战
  • 前端
  • UI组件

【免费下载链接】rsuite

🧱 A suite of React components .

项目地址:https://gitcode.com/gh_mirrors/rs/rsuite
点击查看免费下载

树形表格是展示具有层级结构关系数据的表格形态,它通过在普通表格中引入“父子节点”与“展开/收起”交互,让数据之间的归属关系一目了然。本指南以 rsuite 组件库中的Table为核心,完整讲解树形表格的启用方式、层级数据组织、展开状态控制、自定义单元格与甘特图等实战写法,并结合仓库源码说明其底层行为,读完即可在业务项目中落地一套可运行的层级数据表格。

树形表格是什么

树形表格是一种在表格中展示有结构关系(父子层级)数据的呈现方式。与普通平铺表格相比,树形表格能够清晰地展示数据之间的层级关系——例如部门与成员、分类与商品、任务与子任务。rsuite 的Table组件原生支持树形模式,只需一个属性即可开启,不需要额外引入第三方树表库。

从源码结构看,rsuite 的Table组件是对底层rsuite-table的再封装,见 src/Table/Table.tsx,它对外暴露Table.Cell、Table.Column、Table.HeaderCell、Table.ColumnGroup四个子组件,树形相关的渲染与展开逻辑由底层表格引擎承担,rsuite 负责将isTree、expandedRowKeys、rowKey、renderTreeToggle、onExpandChange等属性透传下去。

基本使用:isTree + children 层级数据

启用树形表格只需要两步:

  1. 在Table组件上设置isTree属性;
  2. 让data中的父子关系通过children字段来定义。

典型的数据结构如下:

const data = [ { id: '1', name: 'Car', count: 460, children: [ { id: '1-1', name: 'Mercedes Benz', count: 300 } // ...更多子节点 ] } ]; <Table data={data} isTree rowKey="id">

其中rowKey="id"用于指定行数据的唯一标识字段。树形表格在渲染时会根据rowKey追踪每一行的身份,从而正确记录“哪个节点被展开/收起”;如果没有唯一标识,树形节点的展开状态将无法被可靠地维护。

层级结构可以无限嵌套,即children内部的节点还可以继续拥有自己的children,从而形成多级树。这一点在官方演示“简单甘特图”中体现得很充分(见下文)。

树形表格相关属性速查

与树形表格直接相关的属性如下:

属性类型描述
expandedRowKeysstring[]展开的行的key数组
defaultExpandedRowKeysstring[]默认展开的行的key数组
rowKeystring行数据的唯一标识
renderTreeToggle() => ReactNode自定义展开/关闭节点的图标
onExpandChange(expanded: boolean, rowData: RowData) => void展开/关闭节点的回调函数

使用要点:

  • 受控与默认值:expandedRowKeys是受控属性,传入后由你维护展开集合;如果希望组件自己管理展开状态,并设置“首次渲染时默认展开哪些行”,则使用defaultExpandedRowKeys。除此之外,演示中还出现了defaultExpandAllRows,用于一次性展开全部层级。
  • 回调时机:onExpandChange在节点展开/收起时触发,回调参数为(expanded, rowData),第一个参数是布尔值(展开为true,收起为false),第二个参数是当前行数据。
  • 自定义图标:renderTreeToggle允许你完全替换默认的展开/收起箭头图标。

展开/收起交互的底层依据

展开状态的记录依赖rowKey。从 src/Table/Table.tsx 中可以看到,rsuite 在封装时把rowData与dataKey作为Cell的两个关键属性保留:dataKey既是数据绑定键,也是排序键。树形表格在展开节点时会基于rowKey生成展开集合,并把“当前行是否处于展开态”作为状态附着在行上;因此自定义单元格(Cell)必须能拿到rowData,才能正确渲染每个节点自己的展开/收起图标与缩进层级。

注意:树形表格的自定义单元格,需要将rowData传递给渲染树的Cell,因为在Cell内部将使用它来记录节点的状态(参见 rsuite issue #2666)。

正确写法:

const CustomCell = ({ rowData, ...rest }) => { return ( <Cell rowData={rowData} {...rest}> {rowData.name} </Cell> ); };

如果不把rowData传回Cell,则单元格内部无法感知所在行是否为父节点、是否已展开,树形图标与层级缩进就会出现异常。

完整演示一:基础树形表格

先看一个完整的、可直接运行的树形表格示例(对应官方演示tree.md)。它使用mockTreeData生成三层级数据,第一层为汽车厂商、第二层为燃料类型、第三层为具体车型,并渲染“评分(Rating)”与“价格(Price)”两列:

import { Table } from 'rsuite'; import { faker } from '@faker-js/faker'; import { mockTreeData } from './mock'; const { Column, HeaderCell, Cell } = Table; const data = mockTreeData({ limits: [2, 3, 3], // 每一层的节点数量:第一层 2 个,第二层 3 个,第三层 3 个 labels: layer => { if (layer === 0) { return faker.vehicle.manufacturer(); // 第一层:汽车厂商 } else if (layer === 1) { return faker.vehicle.fuel(); // 第二层:燃料类型 } return faker.vehicle.vehicle(); // 第三层:具体车型 }, getRowData: () => ({ id: faker.string.numeric(5), price: faker.commerce.price({ min: 10000, max: 1000000, dec: 0, symbol: '$' }), rating: faker.finance.amount({ min: 2, max: 5 }) }) }); const App = () => { return ( <Table isTree defaultExpandAllRows bordered cellBordered rowKey="id" height={400} data={data} /** shouldUpdateScroll: 数据更新后是否更新滚动条,关闭后滚动位置保持不变 **/ shouldUpdateScroll={false} onExpandChange={(isOpen, rowData) => { console.log(isOpen, rowData); }} > <Column flexGrow={1}> <HeaderCell>Vehicle 🚗</HeaderCell> <Cell dataKey="label" /> </Column> <Column width={180}> <HeaderCell>Rating ⭐️</HeaderCell> <Cell> {rowData => Array.from({ length: rowData.rating }).map((_, i) => <span key={i}>⭐️</span>) } </Cell> </Column> <Column width={100}> <HeaderCell>Price 💰</HeaderCell> <Cell dataKey="price" /> </Column> </Table> ); }; ReactDOM.render(<App />, document.getElementById('root'));

示例中的几个关键点:

  • mockTreeData是 rsuite 文档工程提供的树形数据生成工具,源码见 docs/utils/mock.ts。它根据limits数组确定每层节点数,通过labels函数按层生成标签,用getRowData注入业务字段,并在非末层节点上自动挂上children数组。
  • 第三列的Cell以函数形式渲染,接收rowData作为参数,依据rating值循环输出星星——这正体现了树形表格单元格可以自由使用行数据。
  • shouldUpdateScroll={false}表示数据更新后不重置滚动条位置,避免每次展开/收起节点时视图跳动。

完整演示二:用树形表格实现简单甘特图

树形表格的典型进阶用法是“简单甘特图”:把项目生命周期按“任务 → 子任务 → 孙任务”组织成树,每一列代表一个日期,单元格按日期范围着色,从而形成可视化进度条效果(对应官方演示gantt.md)。

数据与列定义如下:

import { Table } from 'rsuite'; import { faker } from '@faker-js/faker'; const { Column, ColumnGroup, HeaderCell, Cell } = Table; const data = [ { id: '1', task: 'Project Lifecycle', startDate: '2024-01-01', endDate: '2024-01-31', children: [ { id: '1-1', task: 'Requirements analysis', startDate: '2024-01-01', endDate: '2024-01-05', children: [ { id: '1-1-1', task: 'Gathering requirements', startDate: '2024-01-01', endDate: '2024-01-02' }, { id: '1-1-2', task: 'Documenting requirements', startDate: '2024-01-03', endDate: '2024-01-05' } ] }, // ...Design / Development / Testing / Deployment / Maintenance 等子任务 ] } ]; const columns = Array.from({ length: 31 }).map((_, index) => { return { HeaderCell: props => { return <HeaderCell {...props}>{index + 1}</HeaderCell>; }, Cell: ({ rowData, depth, ...rest }) => { const colors = ['#c8f0c7', '#4cb04f', '#0f9119']; // 不同层级的着色 const startDate = new Date(rowData.startDate); const endDate = new Date(rowData.endDate); const day = index + 1; const inRange = startDate.getDate() <= day && day <= endDate.getDate(); return ( <Cell {...rest} depth={depth} style={{ backgroundColor: inRange ? colors[depth] : 'transparent' }} /> ); } }; }); const App = () => { return ( <Table isTree defaultExpandAllRows bordered cellBordered rowKey="id" autoHeight data={data} rowHeight={30} > <Column width={300} fixed> <HeaderCell>Project Task</HeaderCell> <Cell dataKey="task" style={{ padding: '5px 0' }} /> </Column> {columns.map((column, index) => { return ( <Column key={index} width={40} align="center"> <column.HeaderCell /> <column.Cell /> </Column> ); })} </Table> ); }; ReactDOM.render(<App />, document.getElementById('root'));

这个例子的关键技巧:

  • depth参数:自定义Cell函数签名中的depth表示当前行所处的树形层级(0 表示顶层)。示例用它决定着色颜色colors[depth],层级越深颜色越深,视觉上直接区分任务粒度。
  • 固定任务列:任务列设置width={300} fixed,横向滚动时任务名称列始终可见,日期列在右侧滚动。
  • 按日着色:每个日期列判断当前行startDate/endDate是否覆盖该日,覆盖则填充背景色,形成条形进度效果。
  • autoHeight:让表格高度随内容自适应,配合多层级数据展示完整的甘特图。
  • ColumnGroup:本示例中未实际使用分组表头,但它与Column、HeaderCell、Cell一同由Table导出(见 src/Table/Table.tsx),适合在需要“任务名 + 31 个日期日”这种分组表头结构时使用。

指定树形列:treeCol 属性

默认情况下,表格的第一列会被用作树形列(即展开图标与缩进所在列)。你也可以通过<Table.Column>上的treeCol属性,把任意一列指定为树形列(对应官方演示tree-col.md)。

<Table isTree defaultExpandAllRows bordered cellBordered rowKey="id" height={400} data={data} shouldUpdateScroll={false} onExpandChange={(isOpen, rowData) => { console.log(isOpen, rowData); }} > <Column width={100}> <HeaderCell>Code</HeaderCell> <Cell dataKey="id" /> </Column> <Column flexGrow={1} treeCol> <HeaderCell>Vehicle 🚗</HeaderCell> <Cell dataKey="label" /> </Column> {/* Rating / Price 列略 */} </Table>

这里把treeCol加在了“Vehicle”列上,因此展开/收起图标与层级缩进都出现在该列,而“Code”列保持为普通数据列。这在业务中很实用——例如第一列是“编号”,第二列才是“名称”,此时让名称列承载树形交互更符合阅读习惯。

虚拟化树形表格:大数据的性能方案

树形表格支持虚拟滚动,可以大大提高渲染大量数据的性能(对应官方演示virtualized.md)。启用方式是在Table上同时设置isTree与virtualized:

<Table isTree virtualized defaultExpandAllRows bordered cellBordered rowKey="id" height={400} data={data} shouldUpdateScroll={false} onExpandChange={(isOpen, rowData) => { console.log(isOpen, rowData); }} > <Column flexGrow={1}> <HeaderCell>Vehicle 🚗</HeaderCell> <Cell dataKey="label" /> </Column> <Column width={180}> <HeaderCell>Rating ⭐️</HeaderCell> <Cell> {rowData => Array.from({ length: rowData.rating }).map((_, i) => <span key={i}>⭐️</span>) } </HeaderCell> </Column> <Column width={100}> <HeaderCell>Price 💰</HeaderCell> <Cell dataKey="price" /> </Column> </Table>

虚拟化示例中使用了limits: [10, 20, 40]的数据规模(首层 10、次层 20、末层 40,共 10 + 200 + 800 = 1010 行),直观验证了在大量层级节点下表格仍能流畅滚动。其原理是:虚拟滚动只渲染视口范围内可见的行,行数据量再大,DOM 节点数量也保持恒定,从而避免一次性渲染全部行导致的内存与渲染开销。

使用虚拟化时的注意点:

  • 建议与rowKey配合使用,让虚拟滚动器能够稳定识别每一行;
  • 树形表格的展开状态仍需通过rowKey维护,展开大量节点后视口外的行同样不会被创建,滚动到对应位置时才渲染;
  • height用于约束可视区域高度,是虚拟滚动生效的前提之一。

在文档工程中查看与复现这些演示

以上四个演示(树形展示、简单甘特图、指定树形列、虚拟化树形表格)均来自本仓库文档工程的 fragments 目录,对应的 Markdown 片段文件分别为:

  • tree.md
  • gantt.md
  • tree-col.md
  • virtualized.md

这些片段由页面入口 index.tsx 注入示例容器。该入口通过 docs/utils/mock.ts 中的mockTreeData生成示例数据,并把mock.js作为沙箱文件一并提供给在线运行环境(CodeSandbox),因此你既可以在文档页面上直接交互体验,也可以把示例代码复制到自己的 React + rsuite 项目中运行。

小结

  • 树形表格用于展示有层级结构的数据,开启方式是在Table上设置isTree,并用children组织父子关系,用rowKey标注行唯一标识。
  • 展开状态由expandedRowKeys(受控)/defaultExpandedRowKeys(初始默认值)/defaultExpandAllRows(全部展开)控制,通过onExpandChange感知展开事件,通过renderTreeToggle自定义图标。
  • 自定义单元格必须把rowData回传给Cell,否则树形状态无法正常记录与渲染。
  • 默认使用第一列作为树形列,可用Column上的treeCol属性改为指定列。
  • 数据量大时可同时开启isTree与virtualized获得虚拟滚动能力,示例表明在约千行的三层级数据下依然流畅。
  • 前端
  • UI组件

【免费下载链接】rsuite

🧱 A suite of React components .

项目地址:https://gitcode.com/gh_mirrors/rs/rsuite
点击查看免费下载

相关推荐

上一篇:3分钟掌握GB/T 7714—2015引用规范:终极CSL样式库指南
下一篇:Super Productivity:重新定义你的智能效率工具

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 2:10:11

Wand-Enhancer:本地 3 分钟解锁 Pro

Wand-Enhancer&#xff1a;本地 3 分钟解锁 Pro 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/GitHub_Trending/we/Wand-Enhancer Wand-Enhancer 是一个开源工具&#xff0c;通过本地…

作者头像 李华
网站建设 2026/10/7 2:09:50

Eve REST API 自定义 ID 字段实战:为资源接入 UUID 唯一标识

后端Web框架 【免费下载链接】eve REST API framework designed for human beings 项目地址&#xff1a; https://gitcode.com/gh_mirrors/ev/eve 点击查看 免费下载 Eve 默认以 MongoDB 的 ObjectId 作为文档唯一标识&#xff0c;但当业务集合使用 UUID 等自定义主键时&#…

作者头像 李华
网站建设 2026/10/7 2:08:03

C# OPC UA客户端开发实战:连接、订阅与SQL Server数据存储

简介&#xff1a;这是一份面向工业自动化、物联网及企业级数据集成方向开发者的C#实战项目源码&#xff0c;核心是用C#构建OPC UA客户端&#xff0c;连接OPC UA服务器完成数据读写&#xff0c;并将采集数据存入SQL Server数据库。项目借助OpcUaHelper开源库简化协议实现&#x…

作者头像 李华
网站建设 2026/10/7 2:07:59

2026 Android Studio 保姆级安装配置指南:从下载到跑通全流程

2026 年了&#xff0c;还有人在 Android Studio 安装配置这一步卡住&#xff0c;而且卡住的原因往往不是技术难题&#xff0c;而是信息太散、教程太旧、版本对不上。你搜“Android Studio 安装教程”能搜出几百篇&#xff0c;但一半是 2019 年的截图&#xff0c;一半讲的是过时…

作者头像 李华