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

基于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="行操作">&nbsp;</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="行操作">&nbsp;</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="行操作">&nbsp;</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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 17:37:35