You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Mat-table指令实现含可变数量子行的表格?

用Angular Material Table实现可变子行表格

核心思路

不需要创建大量行模板,而是先扁平化数据源,将每个学生的主行和对应的多条报告子行整合为一个统一的数组,给每个条目标记类型(主行/子行),再通过multiTemplateDataRows和多套*matRowDef来渲染不同类型的行。

步骤1:定义整合后的数据源类型

先扩展数据结构,用来区分主行和子行:

// 整合后的行数据类型
type TableRow = 
  | { type: 'header', student: string }
  | { type: 'report', report: Report };

// 原数据接口不变
interface ReportCard {
  student: string;
  reports: Report[];
}

interface Report {
  class: string;
  teacher: string;
  grade: string;
}

步骤2:扁平化原数据源

在组件中把原始的ReportCard数组转换为TableRow数组:

import { Component } from '@angular/core';

@Component({
  selector: 'table-basic-example',
  templateUrl: 'table-basic-example.html',
  styleUrls: ['table-basic-example.css'],
})
export class TableBasicExample {
  // 原始示例数据
  originalData: ReportCard[] = [
    {
      student: '张三',
      reports: [
        { class: '数学', teacher: '王老师', grade: 'A' },
        { class: '英语', teacher: '李老师', grade: 'B+' }
      ]
    },
    {
      student: '李四',
      reports: [
        { class: '语文', teacher: '张老师', grade: 'A-' }
      ]
    }
  ];

  // 扁平化后的表格数据源
  dataSource: TableRow[] = [];

  // 表格列定义
  displayedColumns = ['student', 'class', 'teacher', 'grade'];

  ngOnInit() {
    this.flattenData();
  }

  private flattenData() {
    this.originalData.forEach(card => {
      // 添加主行
      this.dataSource.push({ type: 'header', student: card.student });
      // 添加该学生的所有报告子行
      card.reports.forEach(report => {
        this.dataSource.push({ type: 'report', report });
      });
    });
  }
}

步骤3:编写表格模板

利用multiTemplateDataRows启用多模板行渲染,针对不同type配置对应的*matRowDef:

<table mat-table [dataSource]="dataSource" multiTemplateDataRows class="mat-elevation-z8">

  <!-- 学生名列 -->
  <ng-container matColumnDef="student">
    <th mat-header-cell *matHeaderCellDef> 学生 </th>
    <td mat-cell *matCellDef="let row" [attr.colspan]="row.type === 'header' ? 4 : 1">
      {{ row.type === 'header' ? row.student : '' }}
    </td>
  </ng-container>

  <!-- 课程列 -->
  <ng-container matColumnDef="class">
    <th mat-header-cell *matHeaderCellDef> 课程 </th>
    <td mat-cell *matCellDef="let row"> {{ row.type === 'report' ? row.report.class : '' }} </td>
  </ng-container>

  <!-- 老师列 -->
  <ng-container matColumnDef="teacher">
    <th mat-header-cell *matHeaderCellDef> 老师 </th>
    <td mat-cell *matCellDef="let row"> {{ row.type === 'report' ? row.report.teacher : '' }} </td>
  </ng-container>

  <!-- 成绩列 -->
  <ng-container matColumnDef="grade">
    <th mat-header-cell *matHeaderCellDef> 成绩 </th>
    <td mat-cell *matCellDef="let row"> {{ row.type === 'report' ? row.report.grade : '' }} </td>
  </ng-container>

  <!-- 主行模板 -->
  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;" [class.header-row]="row.type === 'header'"></tr>

</table>

步骤4:添加样式优化(可选)

给主行加样式区分:

.header-row {
  background-color: #f5f5f5;
  font-weight: bold;
}

关键说明

  • 通过扁平化数据,避免了创建大量模板,不管每个学生有多少报告,都只用两套行逻辑处理。
  • 主行通过colspan="4"占据所有列,子行正常填充对应列数据。
  • 利用row.type判断当前行类型,渲染对应内容。

内容的提问来源于stack exchange,提问作者ahong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 19:13:29