Angular mat-tree数据源更新时自动折叠问题如何解决
问题原因
你自定义的expanded属性不会被mat-tree识别,组件的展开折叠状态统一由treeControl维护,和节点自身挂载的属性没有关系。另外你每次接口返回后直接全量替换this.dataSource.data,会导致Angular重新渲染所有树节点,之前保存的展开状态会被全部重置,默认回到折叠状态。
修复方案
- 废弃自定义的节点
expanded属性,所有展开/折叠状态判断、操作都通过treeControl提供的方法完成,不要自行维护节点展开状态。 - 加载子节点数据时不要全量替换整个数据源,针对当前点击的父节点做局部数据更新,保留原有节点的对象引用,避免状态丢失。
- 子节点数据渲染完成后,主动调用
treeControl的展开方法标记当前节点为展开状态。
修复后的TS代码
// 确认treeControl初始化逻辑正确,扁平树初始化参考如下 treeControl = new FlatTreeControl<ZipFilesFlatNode>( node => node.level, node => node.hasChild ); toggleNode(node:ZipFilesFlatNode){ // 直接通过treeControl判断当前节点展开状态 const isExpanded = this.treeControl.isExpanded(node); if (isExpanded) { this.treeControl.collapse(node); return; } node.isLoading = true; this.api.getRunFile(url).subscribe((res)=>{ node.isLoading = false; // 扁平树场景:找到当前节点位置,将子节点插入到节点后方,不替换全量数据 const nodeIndex = this.dataSource.data.indexOf(node); const updatedData = [...this.dataSource.data]; updatedData.splice(nodeIndex + 1, 0, ...res.data); this.dataSource.data = updatedData; // 主动标记当前节点展开 this.treeControl.expand(node); },err=>{ node.isLoading = false; }) }
修复后的HTML代码
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl"> <mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding> <button mat-icon-button disabled></button> {{node.name}} </mat-tree-node> <mat-tree-node *matTreeNodeDef="let node; when: hasChild" matTreeNodePadding> <button mat-icon-button [attr.aria-label]="'Toggle ' + node.name" (click)="toggleNode(node)"> <mat-icon class="mat-icon-rtl-mirror"> <!-- 统一用treeControl判断展开状态 --> {{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}} </mat-icon> </button> {{node.name}} <mat-progress-bar *ngIf="node.isLoading" mode="indeterminate" class="example-tree-progress-bar"></mat-progress-bar> </mat-tree-node> </mat-tree>
如果使用嵌套树(NestedTreeControl)场景,不需要手动拼接扁平数据列表,直接把接口返回的子节点赋值给当前节点的
children属性,再调用this.treeControl.expand(node)即可正常保留展开状态。
内容的提问来源于stack exchange,提问作者Vikash Mishra
相关产品推荐
相关产品推荐

