如何在不使用@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
相关产品推荐
相关产品推荐

