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

如何在不使用@Input的情况下打造可配置的通用Angular图标组件?

打造Angular通用图标组件的可行方案

针对你提到的无法使用@Input、需要通过frameworkComponents配置的场景,这里提供几个实用的方案来实现通用图标组件,消除代码冗余:

方案一:抽象基类+组件继承

把两个组件的公共逻辑抽成抽象基类,差异部分定义为抽象方法让子类实现,既复用公共代码,又保留各自的定制逻辑。

示例代码

首先创建抽象基类:

import { Component } from '@angular/core';
import { ICellRendererAngularComp } from 'ag-grid-angular';

export abstract class BaseIconRenderer implements ICellRendererAngularComp {
  params: any;

  // 公共初始化逻辑,子类可复用
  protected commonInit(params: any) {
    this.params = params;
    // 这里放两个组件都有的初始化代码
  }

  // 抽象方法:子类实现图标渲染(也可直接在子类模板中定义)
  abstract renderIcon(): void;

  // 抽象方法:子类实现自定义agInit逻辑
  abstract agInit(params: any): void;
}

然后实现DeleteRowIconComponent:

import { Component } from '@angular/core';
import { BaseIconRenderer } from './base-icon-renderer';

@Component({
  template: '<i class="icon-delete" (click)="onDeleteClick()"></i>'
})
export class DeleteRowIconComponent extends BaseIconRenderer {
  agInit(params: any) {
    this.commonInit(params);
    // 这里写DeleteRow特有的初始化逻辑
  }

  renderIcon() {}

  onDeleteClick() {
    this.params.api.deleteRow(this.params.node);
  }
}

RemoveIconRenderComponent同理,只需替换图标类名、实现自身的agInit和点击逻辑即可。

方案二:通用组件+注入令牌+工厂函数

创建一个通用图标组件,通过Angular注入令牌传递图标配置和逻辑,在frameworkComponents中用工厂函数生成不同实例。

示例代码

先定义配置接口和注入令牌:

import { InjectionToken } from '@angular/core';

export interface IconConfig {
  iconClass: string;
  initHandler: (params: any) => void;
  clickHandler: (params: any) => void;
}

export const ICON_CONFIG = new InjectionToken<IconConfig>('ICON_CONFIG');

然后实现通用组件:

import { Component, Inject } from '@angular/core';
import { ICellRendererAngularComp } from 'ag-grid-angular';
import { ICON_CONFIG, IconConfig } from './icon-config';

@Component({
  template: '<i [class]="iconConfig.iconClass" (click)="handleClick()"></i>'
})
export class GenericIconRenderer implements ICellRendererAngularComp {
  params: any;

  constructor(@Inject(ICON_CONFIG) public iconConfig: IconConfig) {}

  agInit(params: any) {
    this.params = params;
    this.iconConfig.initHandler(params);
  }

  handleClick() {
    this.iconConfig.clickHandler(this.params);
  }
}

在模块中配置工厂提供者:

import { NgModule } from '@angular/core';
import { GenericIconRenderer } from './generic-icon-renderer';
import { ICON_CONFIG, IconConfig } from './icon-config';

@NgModule({
  declarations: [GenericIconRenderer],
  providers: [
    {
      provide: 'DeleteRowIcon',
      useFactory: () => {
        const config: IconConfig = {
          iconClass: 'icon-delete',
          initHandler: (params) => { /* DeleteRow初始化逻辑 */ },
          clickHandler: (params) => params.api.deleteRow(params.node)
        };
        return new GenericIconRenderer(config);
      }
    },
    {
      provide: 'RemoveIcon',
      useFactory: () => {
        const config: IconConfig = {
          iconClass: 'icon-remove',
          initHandler: (params) => { /* Remove初始化逻辑 */ },
          clickHandler: (params) => { /* Remove点击逻辑 */ }
        };
        return new GenericIconRenderer(config);
      }
    }
  ]
})
export class IconModule {}

最后在frameworkComponents中配置:

frameworkComponents: {
  deleteRowIcon: () => inject('DeleteRowIcon'),
  removeIcon: () => inject('RemoveIcon')
}

方案三:通用组件+静态属性配置

创建通用组件,通过静态属性定义图标类和逻辑,子类只需覆盖静态属性即可快速定制。

示例代码

通用组件实现:

import { Component } from '@angular/core';
import { ICellRendererAngularComp } from 'ag-grid-angular';

@Component({
  template: '<i [class]="getIconClass()" (click)="handleClick()"></i>'
})
export class GenericIconComponent implements ICellRendererAngularComp {
  params: any;
  // 静态属性:子类可覆盖
  static iconClass = '';
  static initHandler: (params: any) => void = () => {};
  static clickHandler: (params: any) => void = () => {};

  agInit(params: any) {
    this.params = params;
    (this.constructor as typeof GenericIconComponent).initHandler(params);
  }

  getIconClass() {
    return (this.constructor as typeof GenericIconComponent).iconClass;
  }

  handleClick() {
    (this.constructor as typeof GenericIconComponent).clickHandler(this.params);
  }
}

创建定制子类:

import { Component } from '@angular/core';
import { GenericIconComponent } from './generic-icon.component';

@Component({ template: '' }) // 复用父组件模板
export class DeleteRowIconComponent extends GenericIconComponent {
  static iconClass = 'icon-delete';
  static initHandler(params: any) { /* DeleteRow初始化逻辑 */ }
  static clickHandler(params: any) {
    params.api.deleteRow(params.node);
  }
}

@Component({ template: '' })
export class RemoveIconRenderComponent extends GenericIconComponent {
  static iconClass = 'icon-remove';
  static initHandler(params: any) { /* Remove初始化逻辑 */ }
  static clickHandler(params: any) { /* Remove点击逻辑 */ }
}

直接在frameworkComponents中配置这两个子类即可,无需额外处理。

内容的提问来源于stack exchange,提问作者Rebai Ahmed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 04:20:33