基于Angular Material Table实现多层动态嵌套表格需求
Angular Material Table 实现5-6级嵌套树形表格结构
基于Angular Material Table组件,实现支持5-6级动态子表格的树形嵌套结构,所有层级复用相同数据源,仅使用Angular Material完成开发。
HTML 模板
<table mat-table [dataSource]="dataSource" multiTemplateDataRows class="mat-elevation-z8"> @for (column of columnsToDisplay; track column) { <ng-container matColumnDef="{{column}}"> <th mat-header-cell *matHeaderCellDef> {{column}} </th> <td mat-cell *matCellDef="let element"> {{element[column]}} </td> </ng-container> } <ng-container matColumnDef="expand"> <th mat-header-cell *matHeaderCellDef aria-label="行操作"> </th> <td mat-cell *matCellDef="let element"> <button mat-icon-button aria-label="展开行" (click)="(expandedElement = expandedElement === element ? null : element); $event.stopPropagation()"> @if (expandedElement === element) { <mat-icon>keyboard_arrow_up</mat-icon> } @else { <mat-icon>keyboard_arrow_down</mat-icon> } </button> </td> </ng-container> <!-- 展开内容列 - 详情行由这一列组成,跨所有列 --> <ng-container matColumnDef="expandedDetail"> <td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplayWithExpand.length"> <!-- 二级子表格 --> <table mat-table [dataSource]="dataSource" multiTemplateDataRows class="mat-elevation-z8 ml-4"> @for (column of columnsToDisplay; track column) { <ng-container matColumnDef="{{column}}"> <th mat-header-cell *matHeaderCellDef> {{column}} </th> <td mat-cell *matCellDef="let element"> {{element[column]}} </td> </ng-container> } <ng-container matColumnDef="expand"> <th mat-header-cell *matHeaderCellDef aria-label="行操作"> </th> <td mat-cell *matCellDef="let element"> <button mat-icon-button aria-label="展开行" (click)="(expandedElement = expandedElement === element ? null : element); $event.stopPropagation()"> @if (expandedElement === element) { <mat-icon>keyboard_arrow_up</mat-icon> } @else { <mat-icon>keyboard_arrow_down</mat-icon> } </button> </td> </ng-container> <!-- 三级子表格容器 --> <ng-container matColumnDef="expandedDetail"> <td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplayWithExpand.length"> <!-- 三级子表格,如需扩展到5-6级,重复此嵌套结构即可 --> <table mat-table [dataSource]="dataSource" multiTemplateDataRows class="mat-elevation-z8 ml-4"> @for (column of columnsToDisplay; track column) { <ng-container matColumnDef="{{column}}"> <th mat-header-cell *matHeaderCellDef> {{column}} </th> <td mat-cell *matCellDef="let element"> {{element[column]}} </td> </ng-container> } <ng-container matColumnDef="expand"> <th mat-header-cell *matHeaderCellDef aria-label="行操作"> </th> <td mat-cell *matCellDef="let element"> <button mat-icon-button aria-label="展开行" (click)="(expandedElement = expandedElement === element ? null : element); $event.stopPropagation()"> @if (expandedElement === element) { <mat-icon>keyboard_arrow_up</mat-icon> } @else { <mat-icon>keyboard_arrow_down</mat-icon> } </button> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="columnsToDisplayWithExpand"></tr> <tr mat-row *matRowDef="let element; columns: columnsToDisplayWithExpand;" class="example-element-row" [class.example-expanded-row]="expandedElement === element" (click)="expandedElement = expandedElement === element ? null : element"> </tr> <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr> </table> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="columnsToDisplayWithExpand"></tr> <tr mat-row *matRowDef="let element; columns: columnsToDisplayWithExpand;" class="example-element-row" [class.example-expanded-row]="expandedElement === element" (click)="expandedElement = expandedElement === element ? null : element"> </tr> <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr> </table> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="columnsToDisplayWithExpand"></tr> <tr mat-row *matRowDef="let element; columns: columnsToDisplayWithExpand;" class="example-element-row" [class.example-expanded-row]="expandedElement === element" (click)="expandedElement = expandedElement === element ? null : element"> </tr> <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr> </table>
TypeScript 组件代码
import { Component, trigger, state, style, animate, transition } from '@angular/core'; import { MatTableModule } from '@angular/material/table'; import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; @Component({ selector: 'table-expandable-rows-example', templateUrl: './table-expandable-rows-example.component.html', styleUrls: ['./table-expandable-rows-example.component.css'], standalone: true, imports: [MatTableModule, MatIconModule, MatButtonModule], animations: [ trigger('detailExpand', [ state('collapsed,void', style({height: '0px', minHeight: '0'})), state('expanded', style({height: '*'})), transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), ]), ], }) export class TableExpandableRowsExample { dataSource = ELEMENT_DATA; columnsToDisplay = ['name', 'weight', 'symbol', 'position']; columnsToDisplayWithExpand = [...this.columnsToDisplay, 'expand']; expandedElement: PeriodicElement | null; } // 元素数据接口 export interface PeriodicElement { name: string; // 元素名称 position: number; // 序号 weight: number; // 原子量 symbol: string; // 元素符号 description: string; // 描述信息 } // 示例数据源,所有层级复用该数据 const ELEMENT_DATA: PeriodicElement[] = [ { position: 1, name: '氢', weight: 1.0079, symbol: 'H', description: `氢是一种化学元素,符号为H,原子序数为1。标准原子量为1.008,是元素周期表中最轻的元素。`, }, { position: 2, name: '氦', weight: 4.0026, symbol: 'He', description: `氦是一种化学元素,符号为He,原子序数为2。它是一种无色、无味、无臭、无毒的惰性单原子气体,位于元素周期表的稀有气体组。它的沸点是所有元素中最低的。`, }, ];
实现说明
- 利用
multiTemplateDataRows属性启用多行模板,实现行的展开/折叠功能 - 所有层级子表格复用同一
dataSource,满足“每次注入相同数据”的要求 - 如需扩展到5-6级,只需在当前子表格的
expandedDetail列中重复嵌套相同结构的表格即可 - 添加
ml-4类实现层级缩进,提升树形结构的视觉辨识度 - 通过Angular动画实现展开/折叠的平滑过渡效果
内容的提问来源于stack exchange,提问作者Cyndélia Guillaume
相关产品推荐
相关产品推荐

