基于Angular Material的mat-table实现可展开表格的技术问询
Angular Material mat-table 实现可展开子行的方案解析
嘿,我来给你梳理下用 Angular Material 的 mat-table 实现可展开子行的思路,刚好你提到的两个问题都有明确的解决方案:
1. 能不能在同一次迭代中生成多种行类型?
其实 mat-table 支持通过多组 matRowDef + 条件判断来渲染不同类型的行,但严格来说,数据源的每一项在迭代时只会匹配一种 matRowDef。不过我们可以通过给数据项标记类型(比如父行/子行),让同一份数据源里的不同项分别匹配对应的行模板,从而在同一个表格里呈现两种行类型。
举个简单的例子:给每个数据项加个 isParent 标记,然后定义两组行模板:
<mat-table [dataSource]="flatDataSource"> <!-- 父行模板:仅匹配标记为父行的数据 --> <ng-container matRowDef="let row" when="row.isParent" [matRowDefColumns]="parentColumns"> <mat-row (click)="row.expanded = !row.expanded" class="parent-row"></mat-row> </ng-container> <!-- 子行模板:仅匹配标记为子行的数据 --> <ng-container matRowDef="let row" when="!row.isParent" [matRowDefColumns]="childColumns"> <mat-row class="child-row" *ngIf="row.parent.expanded"></mat-row> </ng-container> </mat-table>
这里的 flatDataSource 是把父项和子项都扁平化后的数组,子项关联对应的父项,点击父行时切换展开状态,控制子行的显示。
2. 是否必须将子项添加到 mat-table 的数据源中?
完全不需要! 这也是很多人容易误解的点,除了扁平化数据源的方式,还有更贴合你原始数据结构的方案:在父行的展开面板中嵌套子表格。
这种方式不需要修改原始的嵌套数据结构,直接利用父对象的 children 属性渲染子行,示例代码如下:
<mat-table [dataSource]="parentDataSource"> <!-- 父行列定义 --> <ng-container matColumnDef="name"> <mat-header-cell *matHeaderCellDef> 名称 </mat-header-cell> <mat-cell *matCellDef="let item"> {{ item.name }} </mat-cell> </ng-container> <!-- 展开按钮列 --> <ng-container matColumnDef="expand"> <mat-header-cell *matHeaderCellDef></mat-header-cell> <mat-cell *matCellDef="let item"> <button mat-icon-button (click)="item.expanded = !item.expanded"> <mat-icon>{{ item.expanded ? 'expand_less' : 'expand_more' }}</mat-icon> </button> </mat-cell> </ng-container> <!-- 父行模板,展开时显示子表格 --> <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row> <mat-row *matRowDef="let item; columns: displayedColumns;"> <!-- 展开面板:用 colspan 占满所有列 --> <mat-cell colspan="100" *ngIf="item.expanded"> <mat-table [dataSource]="item.children" class="child-table"> <!-- 子表格列定义 --> <ng-container matColumnDef="childName"> <mat-header-cell *matHeaderCellDef> 子项名称 </mat-header-cell> <mat-cell *matCellDef="let child"> {{ child.name }} </mat-cell> </ng-container> <mat-header-row *matHeaderRowDef="childColumns"></mat-header-row> <mat-row *matRowDef="let child; columns: childColumns;"></mat-row> </mat-table> </mat-cell> </mat-row> </mat-table>
这个方案里,主表格的数据源只有父项,子项完全不需要加入主数据源,点击父行时直接渲染嵌套的子表格,逻辑更清晰,也更贴合你“父对象包含子对象”的原始数据结构。
两种方案的选择建议
- 如果子行和父行的结构、样式高度统一,且需要对所有行(包括子行)进行全局排序、过滤等操作,推荐用扁平化数据源的方式;
- 如果子行结构和父行差异较大,或者不想破坏原始数据的嵌套结构,嵌套子表格的方式会更合适。
内容的提问来源于stack exchange,提问作者NanoPish
相关产品推荐
相关产品推荐

