You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 13:54:08