如何在Angular 5中创建可复用的Angular Material数据表组件
打造可复用的Angular Material数据表组件
我完全懂你的痛点——重复写Angular Material表格代码真的太繁琐了!下面我来教你一步步打造一个高度可复用的数据表组件,以后再也不用复制粘贴那些重复的模板和逻辑了,只需要传入你的数据和配置就能快速生成表格。
第一步:创建通用数据表组件
首先咱们生成一个新的Angular组件,比如叫data-table:
ng generate component data-table
第二步:定义配置接口
在组件的.ts文件里,先定义几个接口来规范传入的配置,这样代码更清晰也更易维护:
// data-table.component.ts import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core'; import { MatSort } from '@angular/material/sort'; import { MatPaginator } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; // 定义列配置接口 export interface TableColumn<T> { columnDef: string; header: string; isSortable?: boolean; // 是否支持排序 cell: (element: T) => string; // 单元格内容渲染函数 } // 定义动作按钮接口 export interface TableAction { label: string; action: string; // 用来标识动作类型,比如'edit'/'delete' routerLink?: (element: any) => string; // 如果是路由跳转,返回链接 } // 定义表格整体配置接口 export interface TableConfig<T> { data: T[]; columns: TableColumn<T>[]; actions?: TableAction[]; // 可选的动作列 pageSizeOptions?: number[]; // 分页选项 defaultSort?: { active: string; direction: 'asc' | 'desc' }; // 默认排序 }
第三步:实现组件逻辑
接下来在组件类里处理输入的配置,初始化数据源、排序、分页:
@Component({ selector: 'app-data-table', templateUrl: './data-table.component.html', styleUrls: ['./data-table.component.scss'] }) export class DataTableComponent<T> { @Input() set config(config: TableConfig<T>) { if (config) { this._config = config; this.dataSource = new MatTableDataSource(config.data); // 设置排序 if (this.sort && config.defaultSort) { this.sort.active = config.defaultSort.active; this.sort.direction = config.defaultSort.direction; this.dataSource.sort = this.sort; } // 设置分页 if (this.paginator) { this.dataSource.paginator = this.paginator; } // 整理要显示的列(包括动作列) this.displayedColumns = config.columns.map(col => col.columnDef); if (config.actions && config.actions.length > 0) { this.displayedColumns.push('actions'); } } } get config(): TableConfig<T> { return this._config; } private _config: TableConfig<T>; dataSource: MatTableDataSource<T>; displayedColumns: string[] = []; @ViewChild(MatSort) sort: MatSort; @ViewChild(MatPaginator) paginator: MatPaginator; // 触发动作事件,父组件可以监听 @Output() actionTriggered = new EventEmitter<{ action: string; element: T }>(); // 处理动作按钮点击 onAction(action: TableAction, element: T) { if (action.action) { this.actionTriggered.emit({ action: action.action, element }); } } }
第四步:编写组件模板
现在写动态渲染的模板,根据传入的配置生成列、表头和单元格:
<!-- data-table.component.html --> <div class="example-container"> <mat-table [dataSource]="dataSource" matSort> <!-- 动态渲染普通列 --> <ng-container *ngFor="let column of config.columns" [matColumnDef]="column.columnDef"> <mat-header-cell *matHeaderCellDef mat-sort-header="{{column.isSortable ? column.columnDef : ''}}"> {{column.header}} </mat-header-cell> <mat-cell *matCellDef="let element"> {{column.cell(element)}} </mat-cell> </ng-container> <!-- 动作列(如果有配置) --> <ng-container *ngIf="config.actions?.length > 0" matColumnDef="actions"> <mat-header-cell *matHeaderCellDef>Action</mat-header-cell> <mat-cell *matCellDef="let element"> <a *ngFor="let action of config.actions" [routerLink]="action.routerLink ? action.routerLink(element) : null" class="btn Action-Tab" (click)="action.routerLink || onAction(action, element)" > {{action.label}} </a> </mat-cell> </ng-container> <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row> <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row> </mat-table> <mat-paginator *ngIf="config.pageSizeOptions" [pageSizeOptions]="config.pageSizeOptions" showFirstLastButtons ></mat-paginator> </div>
第五步:在父组件中使用通用表格
现在回到你的位置管理组件,只需要传入配置就能生成表格了,再也不用写重复的表格代码!
// location.component.ts import { Component } from '@angular/core'; import { TableColumn, TableAction, TableConfig } from '../data-table/data-table.component'; import { Location } from './location.model'; // 假设你有Location模型 @Component({ selector: 'app-location', templateUrl: './location.component.html', styleUrls: ['./location.component.scss'] }) export class LocationComponent { locations: Location[] = []; // 你的位置数据 // 定义表格配置 tableConfig: TableConfig<Location> = { data: this.locations, columns: [ { columnDef: 'locationName', header: 'Location Name', isSortable: true, cell: (location) => location.locationName }, { columnDef: 'address', header: 'Address', isSortable: false, cell: (location) => location.address }, { columnDef: 'city', header: 'City', isSortable: true, cell: (location) => location.city }, { columnDef: 'country', header: 'Country', isSortable: true, cell: (location) => location.country }, { columnDef: 'zipcode', header: 'ZipCode', isSortable: false, cell: (location) => location.zipcode }, { columnDef: 'phone', header: 'Phone', isSortable: false, cell: (location) => location.phone }, { columnDef: 'timezone', header: 'TimeZone', isSortable: false, cell: (location) => location.timezone } ], actions: [ { label: 'Edit', action: 'edit', routerLink: (location) => `/admin/location/edit/${location.locationID}` }, { label: 'Delete', action: 'delete' } ], pageSizeOptions: [10, 20, 50, 100], defaultSort: { active: 'locationName', direction: 'asc' } }; // 监听动作事件 onTableAction(event: { action: string; element: Location }) { switch (event.action) { case 'delete': this.deleteLocation(event.element, event.element.locationID); break; // 其他动作可以在这里处理 } } deleteLocation(location: Location, id: number) { // 你的删除逻辑 } }
然后父组件的模板就超级简洁了:
<!-- location.component.html --> <app-data-table [config]="tableConfig" (actionTriggered)="onTableAction($event)" ></app-data-table>
额外优化小技巧
- 可以添加过滤功能,在通用组件里加一个输入框,绑定
dataSource.filter - 支持自定义单元格模板(比如如果需要渲染图标或复杂内容,可以用
ng-content或模板引用) - 把样式也通用化,比如表格的间距、按钮样式可以放在通用组件的scss里
这样一来,你所有需要表格的地方都可以复用这个app-data-table组件,只需要传入不同的配置和数据就行,彻底告别重复代码!
内容的提问来源于stack exchange,提问作者Veda
相关产品推荐
相关产品推荐

