如何在Angular组件中复用Angular Material表格的表头与样式?
解决方案
你的封装思路是完全正确的,这是Angular项目中复用通用表格逻辑的标准实现方案。你遇到的列无法识别的问题,是Angular Material的mat-table的内部机制导致的:mat-table默认只会扫描自身组件模板内定义的matColumnDef指令,通过ng-content从父组件投射进来的列定义默认不在其扫描范围内,因此无法识别。
具体修改步骤
第一步:修改公共表格组件的TS逻辑
在你的app-table-setting组件的ts文件中,添加如下代码:
import { Component, Input, ContentChildren, QueryList, ViewChild, AfterContentInit } from '@angular/core'; import { MatTable, MatColumnDef } from '@angular/material/table'; @Component({ selector: 'app-table-setting', templateUrl: './table-setting.component.html', styleUrls: ['./table-setting.component.scss'] }) export class TableSettingComponent implements AfterContentInit { // 你原有已经定义的输入属性保留即可 @Input() dataSource: any; @Input() displayedColumns: string[] = []; @Input() isLoadingResults = false; @Input() errorLoadingResults = false; @Input() emptyDatasetText = ''; @Input() errorGettingDatasetText = ''; // 新增以下两个查询声明 @ViewChild(MatTable, { static: true }) table: MatTable<any>; @ContentChildren(MatColumnDef) columnDefs: QueryList<MatColumnDef>; ngAfterContentInit() { // 手动将投射进来的列定义注册到表格实例上 this.columnDefs.forEach(columnDef => { this.table.addColumnDef(columnDef); }); // 如果存在动态增删列的场景,还要监听列的变更事件重新注册 this.columnDefs.changes.subscribe(() => { this.columnDefs.forEach(columnDef => { this.table.addColumnDef(columnDef); }); }); } }
第二步:验证原有调用逻辑
你原本的业务组件调用代码不需要做任何修改,只要保证displayedColumns数组中定义的列名和你传入的matColumnDef的属性值完全对应即可正常运行。
实现效果
修改完成后就可以完全达到你期望的复用效果:
- 公共表格组件统一管控加载状态、表格样式、固定表头、空状态/错误状态提示、分页(后续要扩展也可以统一封装)等通用逻辑
- 各业务组件只需要传入业务数据源、列显示配置,以及自定义的列模板、绑定业务事件即可,不需要重复编写表格框架代码
内容的提问来源于stack exchange,提问作者nck
相关产品推荐
相关产品推荐

