求助:如何在Angular中实现带嵌套结构的表格?
Angular 嵌套结构表格实现方案
单层子项场景实现
如果只是单层父项嵌套子项的结构,直接通过rowspan结合*ngFor就能实现,无需复杂逻辑。
1. 定义数据结构
在组件类中定义包含子项的表格数据结构:
interface TableItem { id: number; name: string; category: string; children?: TableItem[]; } // 模拟表格数据 tableData: TableItem[] = [ { id: 1, name: '父项1', category: '分类A', children: [ { id: 11, name: '子项1-1', category: '分类A' }, { id: 12, name: '子项1-2', category: '分类A' } ] }, { id: 2, name: '父项2', category: '分类B', children: [ { id: 21, name: '子项2-1', category: '分类B' } ] }, { id: 3, name: '父项3', category: '分类C', children: [] } ];
2. 模板实现
通过ng-container循环父项,父行单元格使用rowspan跨占自身+子项的行数,子行单独渲染剩余列:
<table border="1" cellpadding="8" cellspacing="0"> <thead> <tr> <th>ID</th> <th>名称</th> <th>分类</th> <th>操作</th> </tr> </thead> <tbody> <ng-container *ngFor="let item of tableData"> <!-- 父行 --> <tr> <td [rowspan]="item.children?.length ? item.children.length + 1 : 1">{{ item.id }}</td> <td [rowspan]="item.children?.length ? item.children.length + 1 : 1">{{ item.name }}</td> <td [rowspan]="item.children?.length ? item.children.length + 1 : 1">{{ item.category }}</td> <td>父项操作</td> </tr> <!-- 子行 --> <tr *ngFor="let child of item.children"> <td>{{ child.id }}</td> <td>{{ child.name }}</td> <td>{{ child.category }}</td> <td>子项操作</td> </tr> </ng-container> </tbody> </table>
多层嵌套场景实现
如果需要支持无限层级的嵌套结构,使用递归组件是最简洁的方案。
1. 创建递归行组件
新建table-row.component.ts,组件自身调用自身来处理多层子项:
import { Component, Input } from '@angular/core'; interface TableItem { id: number; name: string; category: string; children?: TableItem[]; } @Component({ selector: 'app-table-row', template: ` <tr> <td [rowspan]="getTotalRowspan(item)">{{ item.id }}</td> <td [rowspan]="getTotalRowspan(item)">{{ item.name }}</td> <td [rowspan]="getTotalRowspan(item)">{{ item.category }}</td> <td>{{ item.children?.length ? '父项操作' : '普通项操作' }}</td> </tr> <!-- 递归渲染子项 --> <ng-container *ngFor="let child of item.children"> <app-table-row [item]="child"></app-table-row> </ng-container> ` }) export class TableRowComponent { @Input() item!: TableItem; // 递归计算当前项需要跨占的总行数 getTotalRowspan(item: TableItem): number { let total = 1; // 自身占1行 if (item.children?.length) { item.children.forEach(child => { total += this.getTotalRowspan(child); }); } return total; } }
2. 父组件模板使用递归组件
在父组件的模板中引入递归组件,循环渲染顶层数据:
<table border="1" cellpadding="8" cellspacing="0"> <thead> <tr> <th>ID</th> <th>名称</th> <th>分类</th> <th>操作</th> </tr> </thead> <tbody> <app-table-row *ngFor="let item of tableData" [item]="item"></app-table-row> </tbody> </table>
注意事项
- 确保
rowspan计算准确:单层场景直接取子项数量+1,多层场景必须递归统计所有子项的总行数 - 样式可自定义:可以通过CSS替代
border、cellpadding属性,实现更美观的表格样式 - 折叠/扩展功能:若需要点击父项显示/隐藏子项,可在组件中添加
isExpanded状态,通过*ngIf控制子项的渲染
内容的提问来源于stack exchange,提问作者learntech
相关产品推荐
相关产品推荐

