如何用 PrimeNG TreeTable 处理层级数据:懒加载与性能优化实战指南
【免费下载链接】primengThe Most Complete Angular UI Component Library项目地址: https://gitcode.com/GitHub_Trending/pr/primeng
你想把公司的部门架构放进一张表格:一级部门、二级团队、三级人员,普通表格里用缩进撑到第三层就乱了。这正是 PrimeNG 的 TreeTable 树形表格组件处理的典型层级数据场景——它把"层层打开的文件夹"直接铺成行列,展开、折叠、编辑都在一张表里完成。
本文以一个组织架构管理页为例,带你从数据建模走到懒加载和性能优化,每一步都给出能直接套用的关键配置。
什么数据适合用树形表格 🌳
先判断,再动手。两条标准:
适合 TreeTable 的数据
- 天然带父子关系:部门 → 团队 → 人员,订单 → 分类 → 商品
- 目录类结构:文件目录树、地区 → 门店、菜单分组
- 用户需要"下钻":先看概览,点一下才看细节
不适合的情况
- 数据只是平铺列表,层级只是历史遗留字段——普通 Table 更轻
- 关系是"网状"的(节点有多个上级),树结构无法表达,得用图类方案
- 接口返回的是平铺数据带
parent_id:先用一次遍历在服务层转成树,别让模板承担这个逻辑
TreeNode 数据结构怎么写
心智模型一句话:每个节点就是一个小盒子,data装业务数据,children装下一层盒子。
import { TreeNode } from 'primeng/api'; interface DeptInfo { id: string; name: string; head: string; } const depts: TreeNode<DeptInfo>[] = [ { data: { id: '1', name: '研发中心', head: '张一' }, children: [ { data: { id: '1-1', name: '前端组', head: '李二' } } ] }, { data: { id: '2', name: '业务部', head: '赵六' } } ];真正常用的只有三个字段:
data:这一行的业务数据,模板里通过rowData访问children:子节点数组;没有children就是叶子节点,渲染时自动不带展开箭头leaf:懒加载模式下的标记位,告诉组件"这个节点还有没有子级、要不要显示箭头"
完整字段定义(含key、expanded、icon等可选配置)见 packages/primeng/src/api/treenode.ts。官方仓库里也备了一份现成的目录树示例数据,结构可以直接抄:apps/showcase/assets/data/demo/filesystem.json。
三步跑通第一个 Angular 树形表格
第一步:引入模块(独立组件写法)
import { TreeTableModule } from 'primeng/treetable'; @Component({ standalone: true, imports: [TreeTableModule], selector: 'dept-table', templateUrl: './dept-table.html' }) export class DeptTable { depts: TreeNode[] = [/* 上文的组织架构数据 */]; }第二步:准备TreeNode[]数据(上节已给出,接口数据到位后替换即可)。
第三步:模板里写两段——#header定义表头,#body定义每行,展开箭头交给p-treetable-toggler:
<p-treetable [value]="depts" [scrollable]="true" [tableStyle]="{ 'min-width': '32rem' }"> <ng-template #header> <tr> <th>部门</th> <th>负责人</th> </tr> </ng-template> <ng-template #body let-node let-rowData="rowData"> <tr [ttRow]="node"> <td> <p-treetable-toggler [rowNode]="node" /> {{ rowData.name }} </td> <td>{{ rowData.head }}</td> </tr> </ng-template> </p-treetable>三个关键配置别漏:
[value]绑定TreeNode[],这是数据的唯一入口- 行上必须挂
[ttRow]="node",告诉组件这一行对应哪个节点 <p-treetable-toggler [rowNode]="node" />就是展开/折叠箭头,放在你想显示树形缩进的那一列
到这一步,部门架构已经能一层层点开看了。
三个真实场景的写法
TreeTable 懒加载:展开节点才请求子数据
场景:全公司 5000 个节点,一次性拉全量接口,页面直接卡住。
方案:分页只取当前页的"根节点";用户点开某个节点,再按节点 id 单独请求它的子级。官方实现思路见组件源码 packages/primeng/src/treetable/。
关键配置:
<p-treetable [value]="pageNodes" [lazy]="true" [loading]="pending" [paginator]="true" [rows]="10" [totalRecords]="1200" (onLazyLoad)="onPage($event)" (onNodeExpand)="onExpand($event)"> <!-- header / body 同基础示例 --> </p-treetable>pending = false; pageNodes: TreeNode[] = []; // 翻页 / 首屏:只取这一页的根节点 onPage(e: { first: number; rows: number }) { this.pending = true; this.http.get('/api/depts', { params: { first: e.first, rows: e.rows } }) .subscribe(list => (this.pageNodes = list, (this.pending = false))); } // 展开节点:按需拉子级,直接挂回节点 onExpand(e: { node: TreeNode }) { this.http.get(`/api/depts/${e.node.data.id}/children`) .subscribe(children => (e.node.children = children)); }[lazy]="true"打开懒加载,[totalRecords]给分页器一个总数投影(onLazyLoad)在翻页、排序时触发,(onNodeExpand)在展开时触发,两者分工明确- 请求期间让
[loading]="true",表格里会出现加载态,用户不会怀疑页面死了
TreeTable 行内编辑:双击单元格直接改
场景:HR 调整了负责人,希望双击名字就能改,不用跳弹窗。
方案:单元格里放p-treetable-cell-editor,它有两个插槽——output是平时显示的文本,input是双击后出现的输入框;失焦自动保存。
关键配置:
<ng-template #body let-node let-rowData="rowData"> <tr [ttRow]="node"> <td ttEditableColumn> <p-treetable-toggler [rowNode]="node" /> <p-treetable-cell-editor> <ng-template #output>{{ rowData.name }}</ng-template> <ng-template #input> <input type="text" [(ngModel)]="rowData.name" /> </ng-template> </p-treetable-cell-editor> </td> <td ttEditableColumn>{{ rowData.head }}</td> </tr> </ng-template>- 可编辑的
<td>要加ttEditableColumn指令,没加它双击不生效 - 想锁住某列,给该
<td>加[ttEditableColumnDisabled]="true",比如第一列通常保留给展开箭头 - 保存逻辑放在
[(ngModel)]的提交回调或输入框的blur里,别在change里逐字发请求
TreeTable 单列排序:只在同层内调整顺序
场景:按负责人姓名排一下,方便 HR 按人找部门。
方案:表头单元格加排序指令,再配一个排序方向图标。
关键配置:
<ng-template #header> <tr> <th ttSortableColumn="name"> 部门 <p-treetable-sort-icon field="name" /> </th> <th ttSortableColumn="head"> 负责人 <p-treetable-sort-icon field="head" /> </th> </tr> </ng-template>ttSortableColumn="字段名"加在<th>上,点击列头即切换升/降序<p-treetable-sort-icon>负责显示方向箭头- 注意排序语义:树形表格只对同一层的兄弟节点重排,不会把整棵树拍平——这符合"每个部门内部各自有序"的直觉
- 需要关键字过滤时,官方示例库有专门的 filter 示例,思路是给列头加过滤匹配模式再挂一个搜索框,可对照 apps/showcase/doc/treetable/ 下的 filter 演示
TreeTable 性能优化:上线前避坑清单
节点上千时,照单核对一遍:
- 大接口切懒加载:
[lazy]="true"+onNodeExpand,首屏只渲染一页根节点 - 打开滚动容器:
[scrollable]="true",避免所有行撑高整页 DOM - 加载态要可见:
[loading]绑定到真实请求状态,请求结束再置回 - 改完数据要通知视图:给
node.children赋值后,重新给[value]赋新数组引用(如this.depts = [...this.depts]),原地修改可能不触发更新 - 叶子节点别骗组件:懒加载模式下给无子级的节点标
leaf: true,否则箭头点了没反应 - 模板保持轻量:金额格式化、状态映射这类计算挪到服务层,模板里只做取值
- 长表配最小宽度:
tableStyle给个min-width,列数多时不挤成一坨 - 展开层级克制:默认全折叠,别为了"好看"全量
expanded: true
写在最后
层级数据的展示难点不在渲染,而在先想清楚数据该长成什么树——TreeNode 建模对了,懒加载和编辑都是顺手的事。
延伸阅读:
- 完整演示与配置说明:apps/showcase/doc/treetable/
- 组件实现源码:packages/primeng/src/treetable/
下一篇聊聊树形表格里的多选与拖拽调序,同样是组织架构图里高频出现的需求。
【免费下载链接】primengThe Most Complete Angular UI Component Library项目地址: https://gitcode.com/GitHub_Trending/pr/primeng
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考