Angular动态组件间基于Key的DI数据共享问题
可行实现方案
原方案问题分析
你之前的代码无法工作的核心原因是:ComponentView中创建的Injector是局部临时对象,没有被纳入ComponentSettings所在的注入器层级中。ComponentSettings使用的是自身组件继承的注入器(根/父组件注入器),自然无法获取到仅存在于局部注入器中的令牌。
方案一:共享服务管理Key-Value映射(推荐)
通过一个单例服务统一存储不同key对应的data,实现跨组件的数据共享,这是Angular中最常用的跨组件数据传递方式之一。
1. 创建共享数据服务
import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class SharedDataService { private dataStore = new Map<string, BehaviorSubject<any>>(); // 设置/更新数据 setData(key: string, data: any): void { let subject = this.dataStore.get(key); if (!subject) { subject = new BehaviorSubject(data); this.dataStore.set(key, subject); } else { subject.next(data); } } // 获取单次数据 getData(key: string): any { const subject = this.dataStore.get(key); return subject?.value; } // 获取可订阅的数据流(支持响应式更新) observeData(key: string): Observable<any> | null { return this.dataStore.get(key)?.asObservable() ?? null; } }
2. 改造ComponentView
import { Component, Input, OnInit, OnChanges, SimpleChanges } from '@angular/core'; import { SharedDataService } from './shared-data.service'; @Component({ selector: 'app-component-view', template: '' // 替换为你的实际模板 }) export class ComponentView implements OnInit, OnChanges { @Input() key!: string; @Input() data!: string; constructor(private sharedDataService: SharedDataService) {} ngOnInit(): void { this.syncData(); } // 监听data变化,实时更新共享数据 ngOnChanges(changes: SimpleChanges): void { if (changes['data']) { this.syncData(); } } private syncData(): void { this.sharedDataService.setData(this.key, this.data); } }
3. 改造ComponentSettings
import { Component, Input, OnInit, OnDestroy } from '@angular/core'; import { SharedDataService } from './shared-data.service'; import { Subscription } from 'rxjs'; @Component({ selector: 'app-component-settings', template: '' // 替换为你的实际模板 }) export class ComponentSettings implements OnInit, OnDestroy { @Input() key!: string; data: any; private dataSub?: Subscription; constructor(private sharedDataService: SharedDataService) {} ngOnInit(): void { // 初始化获取数据 this.data = this.sharedDataService.getData(this.key); // 订阅数据变化,实现响应式更新 const data$ = this.sharedDataService.observeData(this.key); if (data$) { this.dataSub = data$.subscribe(newData => { this.data = newData; }); } } ngOnDestroy(): void { // 清理订阅,避免内存泄漏 this.dataSub?.unsubscribe(); } }
方案二:动态组件创建时共享注入器
如果必须依赖DI令牌的方式传递数据,需要在动态创建组件时,为同key的组件实例共享同一个注入器。
1. 动态组件容器管理注入器
import { Component, ViewContainerRef, Injector, ComponentFactoryResolver } from '@angular/core'; import { ComponentView } from './component-view.component'; import { ComponentSettings } from './component-settings.component'; @Component({ selector: 'app-dynamic-host', template: '' }) export class DynamicHostComponent { private keyInjectors = new Map<string, Injector>(); constructor( private viewContainerRef: ViewContainerRef, private cfr: ComponentFactoryResolver ) {} // 创建ComponentView实例 createComponentView(key: string, data: string): void { // 创建或更新对应key的注入器 const injector = Injector.create({ providers: [{ provide: key, useValue: data }], parent: this.viewContainerRef.injector // 继承父注入器的依赖 }); this.keyInjectors.set(key, injector); const factory = this.cfr.resolveComponentFactory(ComponentView); const compRef = this.viewContainerRef.createComponent(factory, undefined, injector); compRef.instance.key = key; compRef.instance.data = data; } // 创建ComponentSettings实例 createComponentSettings(key: string): void { const injector = this.keyInjectors.get(key); if (!injector) { throw new Error(`No associated injector found for key: ${key}`); } const factory = this.cfr.resolveComponentFactory(ComponentSettings); const compRef = this.viewContainerRef.createComponent(factory, undefined, injector); compRef.instance.key = key; } }
2. 简化ComponentSettings
import { Component, Input, Inject } from '@angular/core'; @Component({ selector: 'app-component-settings', template: '' // 替换为你的实际模板 }) export class ComponentSettings { @Input() key!: string; // 直接通过DI注入对应key的数据 constructor(@Inject(String) public data: any) {} // 或者保留原写法,通过injector获取 // constructor(private injector: Injector) {} // ngOnInit(): void { // this.data = this.injector.get(this.key); // } }
内容的提问来源于stack exchange,提问作者Yurii Hierts
相关产品推荐
相关产品推荐

