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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 20:55:51