Angular泛型指令中初始化的变量为何表现为单例?
问题分析
- 单例数据问题根源:你在
RootDirective里把activator方法本身赋值给了data,而非调用方法创建实例。所有组件继承后共享同一个函数引用,后续对data的修改会让所有组件指向同一个对象,导致单例问题。 - JSON.stringify为空:因为
data实际是个函数,不是接口实例,所以序列化后得到空字符串。 - 构造函数初始化报错:你尝试在构造函数中初始化时,大概率是想直接注入接口类型,但TypeScript接口在运行时会被擦除,Angular无法解析对应的令牌。
修复方案
1. 将接口改为可实例化的类
接口在运行时不存在,无法用来创建实例,所以把ISelectData改成类:
export class SelectData { keyId: string = ''; value: any = null; controlName: string = ''; controlId: string = ''; instanceId: string = ''; anchorCaption: string = ''; placeholder: string = ''; sort: boolean = false; single: boolean = false; filterValue: string = ''; }
2. 修改根指令,正确初始化独立实例
让组件传入数据类的构造函数,在指令中为每个组件创建专属实例:
import { Directive, Input } from '@angular/core'; @Directive({ selector: 'app-root-directive' }) export class RootDirective<T> { @Input() dataClass: { new(): T }; // 接收组件传入的类构造函数 data: T; constructor() {} ngOnInit() { // 在ngOnInit中初始化,确保传入的构造函数已就绪 if (this.dataClass) { this.data = new this.dataClass(); } } }
3. 消费组件的使用方式
组件继承根指令后,传入对应的类构造函数:
import { Component } from '@angular/core'; import { RootDirective } from './root.directive'; import { SelectData } from './select-data.model'; @Component({ selector: 'app-multiselect', template: `<!-- 组件模板内容 -->` }) export class MultiselectComponent extends RootDirective<SelectData> { constructor() { super(); this.dataClass = SelectData; // 赋值类构造函数 } }
4. 替代方案:坚持用接口(工厂函数实现)
如果不想把接口改成类,可以在组件中提供工厂函数来创建实例:
// 根指令 @Directive({ selector: 'app-root-directive' }) export class RootDirective<T> { @Input() dataFactory: () => T; data: T; ngOnInit() { if (this.dataFactory) { this.data = this.dataFactory(); } } } // 消费组件 export class MultiselectComponent extends RootDirective<ISelectData> { constructor() { super(); this.dataFactory = () => ({ keyId: '', value: null, controlName: '', controlId: '', instanceId: '', anchorCaption: '', placeholder: '', sort: false, single: false, filterValue: '' }); } }
关键说明
- 每个组件实例都会在
ngOnInit中创建独立的data实例,彻底解决共享单例问题。 - 改用类或工厂函数后,
this.data是真正的实例对象,JSON.stringify能正常序列化。 - 避免直接把方法赋值给变量,必须调用方法创建实例,确保每个组件拥有独立的数据对象。
内容的提问来源于stack exchange,提问作者FairSite2C
相关产品推荐
相关产品推荐

