Angular 5中封装Angular Material组件时如何传递未知属性给子组件?
在Angular 5中传递未定义属性给子组件的解决方案
在Angular里确实没有React那种开箱即用的{...props}属性展开语法,但我们有几种方案可以实现你想要的效果——让父组件直接传递任意属性给子组件,且子组件无需随内部Material组件的属性更新而修改。
推荐方案:继承Material组件类(最贴合你的需求)
既然你是封装Angular Material组件,最优雅的方式是让你的子组件直接继承Material组件的类。这样Material组件的所有输入属性会自动成为你的子组件的输入属性,父组件可以完全按照Material文档的方式使用你的组件,而且当Material组件更新属性时,你只需要同步继承的逻辑即可,无需逐个修改子组件的输入定义。
举个封装mat-table的例子:
import { Component, Input, OnInit } from '@angular/core'; import { MatTable, MatTableDataSource } from '@angular/material/table'; @Component({ selector: 'my-datatable', template: ` <mat-table [dataSource]="dataSource" [pageSize]="pageSize" [pageIndex]="pageIndex" [sort]="sort" [hidePaginator]="hidePaginator" <!-- 这里直接绑定Material Table的所有输入属性 --> > <!-- 你的动态列生成逻辑 --> <ng-container *ngFor="let column of columns" [matColumnDef]="column.key"> <th mat-header-cell *matHeaderCellDef>{{ column.label }}</th> <td mat-cell *matCellDef="let row">{{ row[column.key] }}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="columnKeys"></tr> <tr mat-row *matRowDef="let row; columns: columnKeys;"></tr> </mat-table> ` }) export class MyDatatableComponent extends MatTable<any> implements OnInit { @Input() columns: { key: string; label: string }[]; @Input() data: any[]; dataSource: MatTableDataSource<any>; columnKeys: string[]; ngOnInit() { this.columnKeys = this.columns.map(col => col.key); this.dataSource = new MatTableDataSource(this.data); } }
父组件使用时完全和原生Material组件一致:
<my-datatable [columns]="[{ key: 'name', label: '姓名' }, { key: 'age', label: '年龄' }]" [data]="userList" [pageSize]="15" [sort]="tableSort" [hidePaginator]="false" ></my-datatable>
这种方案的优势:
- 完全遵循Angular组件设计规范
- 开发者可以直接参考Material文档使用你的组件,学习成本低
- Material组件更新属性时,你只需要同步模板中的绑定即可(甚至如果继承逻辑足够完善,无需修改)
备选方案:属性对象+循环绑定(无需继承)
如果你不想继承Material组件类,可以用一个输入对象来收集所有未知属性,再通过keyvalue管道循环绑定到内部组件。这种方式虽然需要把未知属性包裹在对象里,但能保证子组件不随Material组件更新而修改。
子组件代码:
import { Component, Input, OnInit } from '@angular/core'; import { MatTableDataSource } from '@angular/material/table'; @Component({ selector: 'my-datatable', template: ` <mat-table [dataSource]="dataSource" <!-- 循环绑定所有传入的Material属性 --> *ngFor="let prop of matProps | keyvalue" [attr.[prop.key]]="prop.value" > <!-- 动态列逻辑 --> <ng-container *ngFor="let column of columns" [matColumnDef]="column.key"> <th mat-header-cell *matHeaderCellDef>{{ column.label }}</th> <td mat-cell *matCellDef="let row">{{ row[column.key] }}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="columnKeys"></tr> <tr mat-row *matRowDef="let row; columns: columnKeys;"></tr> </mat-table> ` }) export class MyDatatableComponent implements OnInit { @Input() columns: { key: string; label: string }[]; @Input() data: any[]; @Input() matProps: { [key: string]: any } = {}; dataSource: MatTableDataSource<any>; columnKeys: string[]; ngOnInit() { this.columnKeys = this.columns.map(col => col.key); this.dataSource = new MatTableDataSource(this.data); } }
父组件使用方式:
<my-datatable [columns]="columns" [data]="userList" [matProps]="{ pageSize: 15, sort: tableSort, hidePaginator: false, newMaterialProp: 'test' }" ></my-datatable>
这种方案的优势是完全解耦了子组件和Material组件的属性依赖,Material更新属性时你不需要修改子组件,只需要在父组件的matProps中添加新属性即可。
内容的提问来源于stack exchange,提问作者Vap0r
相关产品推荐
相关产品推荐

