动态组件
- 创建锚点:在添加组件之前,先要定义一个锚点来告诉 Angular 要把组件插入到什么地方。使用一个自定义辅助指令来在模板中标记出有效的插入点。
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[ad-host]',
})
export class AdDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
- 加载组件:声明一个<ng-template>,将指令作用到该模板上,Angular 就知道该把组件动态加载到哪里了。
template: `
<div class="ad-banner-example">
<h3>Advertisements</h3>
<ng-template ad-host></ng-template>
</div>
`
- 解析组件:使用 ComponentFactoryResolver 来为每个具体的组件解析出一个 ComponentFactory。 然后 ComponentFactory 会为每一个组件创建一个实例。把 viewContainerRef 指向这个组件的现有实例。因为之前在创建指令时,注入了一个 ViewContainerRef。要把这个组件添加到模板中,你可以调用 ViewContainerRef 的 createComponent()。createComponent() 方法返回一个引用,指向这个刚刚加载的组件。 使用这个引用就可以与该组件进行交互,比如设置它的属性或调用它的方法。
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;
const adItem = this.ads[this.currentAdIndex];
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);
const viewContainerRef = this.adHost.viewContainerRef;
viewContainerRef.clear();
const componentRef = viewContainerRef.createComponent(componentFactory);
(<AdComponent>componentRef.instance).data = adItem.data;
}
getAds() {
this.interval = setInterval(() => {
this.loadComponent();
}, 3000);
}
}
- 引用选择器:要想确保编译器照常生成工厂类,就要把这些动态加载的组件添加到 NgModule 的 entryComponents 数组中
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { HeroJobAdComponent } from './hero-job-ad.component';
import { AdBannerComponent } from './ad-banner.component';
import { HeroProfileComponent } from './hero-profile.component';
import { AdDirective } from './ad.directive';
import { AdService } from './ad.service';
@NgModule({
imports: [ BrowserModule ],
providers: [AdService],
declarations: [ AppComponent,
AdBannerComponent,
HeroJobAdComponent,
HeroProfileComponent,
AdDirective ],
entryComponents: [ HeroJobAdComponent, HeroProfileComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule {
constructor() {}
}