如何动态生成并展示任意层级嵌套的Angular Material Table
实现方案
核心逻辑是通过递归组件实现任意层级的嵌套表格,无需硬编码层级,只要行数据存在子项就可以自动渲染下一级表格。
1. 封装可递归的嵌套表格组件
创建独立的nested-table组件,组件内部可以调用自身,实现层级无限嵌套:
- 组件入参定义:接收
dataSource(当前层级的数据源)、displayedColumns(当前层级要展示的列)两个输入属性即可 - 组件内部直接复用你现有的表格展开逻辑,内层再次调用自身组件渲染下一级
2. 改造行点击懒加载逻辑
你不需要更新整体数据源,因为每一行的element是引用类型,直接给当前点击的element追加_mdbpartchilds属性即可,Angular变更检测会自动同步到绑定的子表格数据源上:
// 写在递归组件的ts文件中 toggleRow(element: any) { // 如果已经加载过子数据,直接切换展开状态 if (element._mdbpartchilds) { element.isExpanded = !element.isExpanded; return; } // 没加载过则调用后端接口拉取子数据 this.yourApiService.getChildData(element.id).subscribe(res => { // 直接给当前行对象挂载子数据源,无需修改上层整体数据源 element._mdbpartchilds = res; element.isExpanded = true; }) }
3. 递归组件模板示例
你现有一级嵌套的代码可以直接复用,只需要把内层的固定表格替换成递归调用自己的组件即可:
<!-- nested-table.component.html 递归组件模板 --> <table mat-table [dataSource]="dataSource" matSort> <!-- 普通列定义 --> <ng-container matColumnDef="{{column}}" *ngFor="let column of displayedColumns"> <th mat-header-cell *matHeaderCellDef mat-sort-header> {{column}} </th> <td mat-cell *matCellDef="let element"> {{element[column]}} </td> </ng-container> <!-- 展开详情列定义 --> <ng-container matColumnDef="expandedDetail"> <td mat-cell *matCellDef="let element" [attr.colspan]="displayedColumns.length"> <div class="example-element-detail" *ngIf="element._mdbpartchilds?.length" [@detailExpand]="element.isExpanded ? 'expanded' : 'collapsed'"> <div class="inner-table mat-elevation-z8"> <!-- 递归调用自身组件,传入子级数据源和列配置 --> <nested-table [dataSource]="element._mdbpartchilds" [displayedColumns]="displayedColumns" ></nested-table> </div> </div> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let element; columns: displayedColumns;" [class.example-element-row]="element._mdbpartchilds?.length || element.hasChildren" [class.example-expanded-row]="element.isExpanded" (click)="toggleRow(element)"> </tr> <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr> </table>
4. 父组件调用
最外层直接调用一次递归组件传入根数据源即可:
<!-- 父组件模板 --> <nested-table [dataSource]="rootDataSource" [displayedColumns]="rootDisplayedColumns" ></nested-table>
可选优化点
- 如果不同层级的展示列不一样,可以给递归组件新增
level输入属性,根据层级切换不同的列配置 - 如果要提前判断某行是否有子项不需要先加载,可以给行数据加
hasChildren标记,点击时再加载子数据,避免无意义的接口请求 - 展开状态如果要支持全局控制,可以用全局Map存储每行的展开状态,不需要挂载到element对象上
内容的提问来源于stack exchange,提问作者Pravin Ambekar.
相关产品推荐
相关产品推荐

