如何在Angular项目中抽离复用PrimeNG Table的ng-template模板片段
PrimeNG Table 模板片段抽离复用方案
针对PrimeNG 12版本的Table组件模板抽离,推荐两种可落地的实现方式,按复用场景选择即可:
方案一:封装通用Table组件(适合全量复用表格逻辑+模板)
适合大部分表格的列渲染、表头、行交互逻辑一致的场景,直接把整个<p-table>封装成共享组件,对外暴露配置入参和事件即可。
步骤1:创建共享Table组件
在共享模块下生成shared-table.component.ts和对应的模板文件:
// shared-table.component.ts import { Component, Input, Output, EventEmitter } from '@angular/core'; import { Table } from 'primeng/table'; @Component({ selector: 'app-shared-table', templateUrl: './shared-table.component.html' }) export class SharedTableComponent { // 表格数据源入参 @Input() data: any[]; // 列配置入参 @Input() columns: any[]; // 行点击事件出参 @Output() rowClick = new EventEmitter<any>(); // 其他需要自定义的配置(分页、排序开关等)都可以在这里扩展入参 }
把原来的<p-table>代码整体迁移到shared-table.component.html,硬编码逻辑替换为入参和事件:
<!-- shared-table.component.html --> <p-table #table [value]="data" [columns]="columns"> <ng-template pTemplate="colgroup" let-columns> <colgroup> <col *ngFor="let col of columns" [ngStyle]="col.style || {}"> </colgroup> </ng-template> <ng-template pTemplate="header" let-columns> <tr> <ng-container *ngFor="let col of columns"> <!-- 保留你的原有表头渲染逻辑,比如取col.label作为表头文字 --> <th>{{ col.label }}</th> </ng-container> </tr> </ng-template> <ng-template pTemplate="body" let-row let-columns="columns" let-expanded="expanded"> <tr (click)="rowClick.emit(row)" [class]="row.rowClass || ''"> <ng-container *ngFor="let column of columns"> <!-- 保留你的原有表体渲染逻辑,比如根据column.field取row对应字段 --> <td>{{ row[column.field] }}</td> </ng-container> </tr> </ng-template> </p-table>
步骤2:共享模块声明导出组件
在SharedModule里声明该组件,同时导出给其他业务模块使用:
// shared.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { TableModule } from 'primeng/table'; import { SharedTableComponent } from './shared-table.component'; @NgModule({ declarations: [SharedTableComponent], imports: [CommonModule, TableModule], exports: [SharedTableComponent] }) export class SharedModule { }
步骤3:业务组件直接调用
原有业务组件不需要再写重复的<p-table>和ng-template,直接调用封装好的组件:
<!-- 业务组件HTML --> <app-shared-table [data]="userDataSource.data$ | async" [columns]="displayedColumns" (rowClick)="rowClicked($event)" ></app-shared-table>
方案二:仅抽离ng-template片段(适合部分复用模板的场景)
如果不需要封装整个表格逻辑,仅想抽离公共模板片段,可以用ngTemplateOutlet配合指令实现:
步骤1:创建共享模板容器
新建模板指令和无逻辑模板容器组件:
// table-templates.directive.ts import { Directive, TemplateRef } from '@angular/core'; @Directive({selector: '[appTableColgroupTemplate]'}) export class TableColgroupTemplateDirective { constructor(public templateRef: TemplateRef<any>) {} } @Directive({selector: '[appTableHeaderTemplate]'}) export class TableHeaderTemplateDirective { constructor(public templateRef: TemplateRef<any>) {} } @Directive({selector: '[appTableBodyTemplate]'}) export class TableBodyTemplateDirective { constructor(public templateRef: TemplateRef<any>) {} }
<!-- table-templates.component.html --> <ng-template appTableColgroupTemplate let-columns> <colgroup> <col *ngFor="let col of columns" [ngStyle]="col.style || {}"> </colgroup> </ng-template> <ng-template appTableHeaderTemplate let-columns> <tr> <ng-container *ngFor="let col of columns"> <th>{{ col.label }}</th> </ng-container> </tr> </ng-template> <ng-template appTableBodyTemplate let-row let-columns="columns" let-expanded="expanded" let-rowClick="rowClick"> <tr (click)="rowClick(row)" [class]="row.rowClass || ''"> <ng-container *ngFor="let column of columns"> <td>{{ row[column.field] }}</td> </ng-container> </tr> </ng-template>
步骤2:业务组件引入模板使用
在业务组件中注入模板,通过ngTemplateOutlet渲染到<p-table>对应位置:
// 业务组件TS import { Component, ViewChild } from '@angular/core'; import { TableTemplatesComponent } from './table-templates.component'; @Component({ selector: 'app-user-table', templateUrl: './user-table.component.html' }) export class UserTableComponent { @ViewChild(TableTemplatesComponent) tableTemplates: TableTemplatesComponent; displayedColumns = []; userDataSource = {data$: of([])}; rowClicked(row: any) { // 原有行点击逻辑 } }
<!-- 业务组件HTML --> <app-table-templates #tableTemplates></app-table-templates> <p-table #table [value]="userDataSource.data$ | async" [columns]="displayedColumns"> <ng-template pTemplate="colgroup" let-columns> <ng-container *ngTemplateOutlet="tableTemplates.colgroupTemplate.templateRef; context: {$implicit: columns}"></ng-container> </ng-template> <ng-template pTemplate="header" let-columns> <ng-container *ngTemplateOutlet="tableTemplates.headerTemplate.templateRef; context: {$implicit: columns}"></ng-container> </ng-template> <ng-template pTemplate="body" let-row let-columns="columns" let-expanded="expanded"> <ng-container *ngTemplateOutlet="tableTemplates.bodyTemplate.templateRef; context: {$implicit: row, columns: columns, expanded: expanded, rowClick: rowClicked}"></ng-container> </ng-template> </p-table>
注意事项
- PrimeNG 12版本的
pTemplate命名要和官方规范保持一致,不要写错模板名 - 模板传递上下文时要对应好
let-xxx的变量名,确保参数传递正确 - 如果有特殊列需要自定义,可在封装组件时预留自定义模板入口,通过
ngTemplateOutlet透传业务侧的自定义模板即可
内容的提问来源于stack exchange,提问作者user3626048
相关产品推荐
相关产品推荐

