angular学习之路9-动态组件

1,

指令

在添加组件之前,先要定义一个锚点来告诉 Angular 要把组件插入到什么地方。

广告条使用一个名叫 AdDirective 的辅助指令来在模板中标记出有效的插入点。

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[ad-host]',
})
export class AdDirective {
  constructor(public viewContainerRef: ViewContainerRef) { }
}

AdDirective 注入了 ViewContainerRef 来获取对容器视图的访问权,这个容器就是那些动态加入的组件的宿主。

在 @Directive 装饰器中,要注意选择器的名称:ad-host,它就是你将应用到元素上的指令。下一节会展示该如何做。

加载组件

<ng-template> 元素就是刚才制作的指令将应用到的地方。 要应用 AdDirective,回忆一下来自 ad.directive.ts的选择器 ad-host。把它应用到 <ng-template>(不用带方括号)。 这下,Angular 就知道该把组件动态加载到哪里了。

template: `
            <div class="ad-banner-example">
              <h3>Advertisements</h3>
              <ng-template ad-host></ng-template>
            </div>
          `

<ng-template> 元素是动态加载组件的最佳选择,因为它不会渲染任何额外的输出。

解析组件

AdBannerComponent 接收一个 AdItem 对象的数组作为输入,它最终来自 AdService。 AdItem 对象指定要加载的组件类,以及绑定到该组件上的任意数据。 AdService 可以返回广告活动中的那些广告。

给 AdBannerComponent 传入一个组件数组可以在模板中放入一个广告的动态列表,而不用写死在模板中。

通过 getAds() 方法,AdBannerComponent 可以循环遍历 AdItems 的数组,并且每三秒调用一次 loadComponent()来加载新组件。

export class AdBannerComponent implements OnInit, OnDestroy {
  @Input() ads: AdItem[];
  currentAdIndex = -1;
  @ViewChild(AdDirective, {static: true}) adHost: AdDirective;
  interval: any;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

  ngOnInit() {
    this.loadComponent();
    this.getAds();
  }

  ngOnDestroy() {
    clearInterval(this.interval);
  }

  loadComponent() {
    this.currentAdIndex = (this.currentAdIndex + 1) % this.ads.length;
    let adItem = this.ads[this.currentAdIndex]; //此处是获取要展示的ads  

    let componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);  //为每个具体的组件解析出一个 ComponentFactory  此 ComponentFactory用来生成组件实例

    let viewContainerRef = this.adHost.viewContainerRef;   //组件需要加载的位置
    viewContainerRef.clear();

    let componentRef = viewContainerRef.createComponent(componentFactory);  //createComponent() 方法返回一个引用,指向这个刚刚加载的组件。 使用这个引用就可以与该组件进行交互
    (<AdComponent>componentRef.instance).data = adItem.data;  // 为组件输入值
  }

  getAds() {
    this.interval = setInterval(() => {
      this.loadComponent();
    }, 3000);
  }
}

在 loadComponent() 选取了一个广告之后,它使用 ComponentFactoryResolver 来为每个具体的组件解析出一个 ComponentFactory。 然后 ComponentFactory 会为每一个组件创建一个实例。

接下来,你要把 viewContainerRef 指向这个组件的现有实例。但你怎么才能找到这个实例呢? 很简单,因为它指向了 adHost,而这个 adHost 就是你以前设置过的指令,用来告诉 Angular 该把动态组件插入到什么位置。

回忆一下,AdDirective 曾在它的构造函数中注入了一个 ViewContainerRef。 因此这个指令可以访问到这个你打算用作动态组件宿主的元素。

要把这个组件添加到模板中,你可以调用 ViewContainerRef 的 createComponent()

createComponent() 方法返回一个引用,指向这个刚刚加载的组件。 使用这个引用就可以与该组件进行交互,比如设置它的属性或调用它的方法。

对选择器的引用

通常,Angular 编译器会为模板中所引用的每个组件都生成一个 ComponentFactory 类。 但是,对于动态加载的组件,模板中不会出现对它们的选择器的引用。

要想确保编译器照常生成工厂类,就要把这些动态加载的组件添加到 NgModule 的 entryComponents 数组中:

entryComponents: [ HeroJobAdComponent, HeroProfileComponent ],

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值