看了Angular官網Hero教程中的動態組件一節,而後還看了一篇講的不錯的文章,結合本身的理解,總結Angular動態組件加載以下:
首先咱們抽象地考慮一下,動態組件加載須要哪些東西?首先你要加載的組件們應該定義出來,其次你須要一個能夠掛載這些動態組件的容器,而且要考慮怎麼把你的組件掛載到容器上。
定義組件很容易,咱們這裏定義兩個最簡單的組件:
動態組件1:bootstrap
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'dy1-component', template: `<div>Dynamic Component 1</div>` }) export class DY1Component implements OnInit { constructor() { } ngOnInit() { } }
動態組件2:ide
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'dy2-component', template: `<div>Dynamic Component 2</div>` }) export class DY2Component implements OnInit { constructor() { } ngOnInit() { } }
定義好的組件必需要在module裏的declarations和entryComponents中聲明:\this
@NgModule({ declarations: [ AppComponent, DY1Component, DY2Component ], entryComponents: [ DY1Component, DY2Component ] imports: [ BrowserModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
Angular中凡是要用到的組件都要在declarations中聲明這好理解,可是爲何要在entryComponents裏面也要去聲明呢?別忘了咱們的組件是動態組件,這意味着angular根本不知道咱們在運行時要加載哪些動態組件,因此angular在編譯階段不會爲這些動態組件進行實例化,可是當運行時咱們須要它的時候,angular得知道啊,這裏就告訴angular這些是動態組件,須要在運行的時候給我臨時建立。其實在entryComponents裏聲明的組件,angular都會建立一個工廠(ComponentFactory)而且存儲在ComponentFactoryResolver(至關於一個工廠集合)中,而後在須要的時候由工廠去建立這些動態組件,後面會詳細說明。
而後咱們就來看看怎麼去把這些動態組件掛載到視圖容器中。咱們定義了一個DynamicComponent的組件以下:code
@Component({ selector: 'dynamic-com', template: ` <section> <button (click)="addComponent()">Add Component</button> <button (click)="stopSwitch()">Stop</button> <section #dmroom></section> </section> ` }) export class DY1ComponentComponent implements OnInit { @ViewChild('dmroom', { read: ViewContainerRef }) dmRoom: ViewContainerRef; currentIndex: number = -1; interval: any; comps: any = [DY1Component, DY2Component]; constructor(private cfr: ComponentFactoryResolver) { } addComponent() { this.interval = setInterval(() => { this.currentIndex = (this.currentIndex + 1) % this.comps.length; let comp = this.comps[this.currentIndex]; let com = this.cfr.resolveComponentFactory(comp); this.dmRoom.clear(); this.dmRoom.createComponent(com); }, 1000); } stopSwitch() { clearInterval(this.interval); } ngOnInit() { } ngOnDestroy() { clearInterval(this.interval); } }
咱們這個組件用一個定時器去不斷循環加載咱們定義的兩個動態組件,用@ViewChild獲取模板中的<section>節點做爲加載的容器,其中{read: ContainerRef}是說把這個節點看成ContainerRef進行解釋,由於ContainerRef能夠去掛載組件。咱們依賴注入了ComponentFactoryResolver,用它來獲取動態組件的工廠,而後ContainerRef調用createComponent完成兩件事:1.利用動態組件的工廠建立出動態組件的實例,2. 把動態組件的實例掛載到ContainerRef中。
至此提一個問題,爲何Angular實現動態組件要用工廠模式而不直接new呢?從上面能夠看到,其實動態組件不單單是須要建立它的實例,還須要考慮如何去加載動態組件到它的宿主元素上,甚至還有其餘的一些額外操做,因此若是咱們僅僅是new一個組件,那麼只是組件的一個很小的部分,或者說只是初始化了組件中的‘一些變量,而組件的不少其餘內容,包括不少DOM操做都沒有去作,而利用組件工廠,angular偏偏幫咱們去作了這些事情,屏蔽了諸如DOM操做的相關內容,因此咱們要用工廠模式去解決動態組件的問題。component