W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
譯注:本頁講的是一個(gè)用于顯示廣告的范例,而部分廣告攔截器插件,比如 Chrome 的 AdGuard,可能會(huì)破壞其工作邏輯,因,請?jiān)诒卷撽P(guān)閉那些插件。
組件的模板不會(huì)永遠(yuǎn)是固定的。應(yīng)用可能會(huì)需要在運(yùn)行期間加載一些新的組件。這本烹飪書為你展示如何使用 ?ComponentFactoryResolver
?來動(dòng)態(tài)添加組件。
到現(xiàn)場演練 / 下載范例查看本節(jié)的源碼。
下面的例子展示了如何構(gòu)建動(dòng)態(tài)廣告條。
英雄管理局正在計(jì)劃一個(gè)廣告活動(dòng),要在廣告條中顯示一系列不同的廣告。幾個(gè)不同的小組可能會(huì)頻繁加入新的廣告組件。 再用只支持靜態(tài)組件結(jié)構(gòu)的模板顯然是不現(xiàn)實(shí)的。
你需要一種新的組件加載方式,它不需要在廣告條組件的模板中引用固定的組件。
Angular 自帶的 API 就能支持動(dòng)態(tài)加載組件。
在添加組件之前,先要定義一個(gè)錨點(diǎn)來告訴 Angular 要把組件插入到什么地方。
廣告條使用一個(gè)名叫 ?AdDirective
?的輔助指令來在模板中標(biāo)記出有效的插入點(diǎn)。
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[adHost]',
})
export class AdDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
?AdDirective
?注入了 ?ViewContainerRef
?來獲取對容器視圖的訪問權(quán),這個(gè)容器就是那些動(dòng)態(tài)加入的組件的宿主。
在 ?@Directive
? 裝飾器中,要注意選擇器的名稱:?ad-host
?,它就是你將應(yīng)用到元素上的指令。下一節(jié)會(huì)展示該如何做。
廣告條的大部分實(shí)現(xiàn)代碼都在 ?ad-banner.component.ts
? 中。 為了讓這個(gè)例子簡單點(diǎn),HTML 被直接放在了 ?@Component
? 裝飾器的 ?template
?屬性中。
?<ng-template>
? 元素就是剛才制作的指令將應(yīng)用到的地方。 要應(yīng)用 ?AdDirective
?,回憶一下來自 ?ad.directive.ts
? 的選擇器 ?ad-host
?。把它應(yīng)用到 ?<ng-template>
?(不用帶方括號)。 這下,Angular 就知道該把組件動(dòng)態(tài)加載到哪里了。
template: `
<div class="ad-banner-example">
<h3>Advertisements</h3>
<ng-template adHost></ng-template>
</div>
`
?<ng-template>
? 元素是動(dòng)態(tài)加載組件的最佳選擇,因?yàn)樗粫?huì)渲染任何額外的輸出。
深入看看 ?ad-banner.component.ts
? 中的方法。
?AdBannerComponent
?接收一個(gè) ?AdItem
?對象的數(shù)組作為輸入,它最終來自 ?AdService
?。 ?AdItem
?對象指定要加載的組件類,以及綁定到該組件上的任意數(shù)據(jù)。 ?AdService
?可以返回廣告活動(dòng)中的那些廣告。
給 ?AdBannerComponent
?傳入一個(gè)組件數(shù)組可以在模板中放入一個(gè)廣告的動(dòng)態(tài)列表,而不用寫死在模板中。
通過 ?getAds()
? 方法,?AdBannerComponent
?可以循環(huán)遍歷 ?AdItems
?的數(shù)組,并且每三秒調(diào)用一次 ?loadComponent()
? 來加載新組件。
export class AdBannerComponent implements OnInit, OnDestroy {
@Input() ads: AdItem[] = [];
currentAdIndex = -1;
@ViewChild(AdDirective, {static: true}) adHost!: AdDirective;
interval: number|undefined;
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 viewContainerRef = this.adHost.viewContainerRef;
viewContainerRef.clear();
const componentRef = viewContainerRef.createComponent<AdComponent>(adItem.component);
componentRef.instance.data = adItem.data;
}
getAds() {
this.interval = setInterval(() => {
this.loadComponent();
}, 3000);
}
}
這里的 ?loadComponent()
? 方法很重要。 來一步步看看。首先,它選取了一個(gè)廣告。
?loadComponent()
? 如何選擇廣告
?loadComponent()
? 方法使用某種算法選擇了一個(gè)廣告。
(譯注:循環(huán)選取算法)首先,它把 ?currentAdIndex
?遞增一,然后用它除以 ?AdItem
?數(shù)組長度的余數(shù)作為新的 ?currentAdIndex
?的值, 最后用這個(gè)值來從數(shù)組中選取一個(gè) ?adItem
?。
接下來,你要把 ?viewContainerRef
?指向這個(gè)組件的現(xiàn)有實(shí)例。但你怎么才能找到這個(gè)實(shí)例呢? 很簡單,因?yàn)樗赶蛄?nbsp;?adHost
?,而這個(gè) ?adHost
?就是你以前設(shè)置過的指令,用來告訴 Angular 該把動(dòng)態(tài)組件插入到什么位置。
回憶一下,?AdDirective
?曾在它的構(gòu)造函數(shù)中注入了一個(gè) ?ViewContainerRef
?。 因此這個(gè)指令可以訪問到這個(gè)你打算用作動(dòng)態(tài)組件宿主的元素。
要把這個(gè)組件添加到模板中,你可以調(diào)用 ?ViewContainerRef
?的 ?createComponent()
?。
?createComponent()
? 方法返回一個(gè)引用,指向這個(gè)剛剛加載的組件。 使用這個(gè)引用就可以與該組件進(jìn)行交互,比如設(shè)置它的屬性或調(diào)用它的方法。
在廣告條中,所有組件都實(shí)現(xiàn)了一個(gè)公共接口 ?AdComponent
?,它定義了一個(gè)標(biāo)準(zhǔn)化的 API,來把數(shù)據(jù)傳給組件。
下面就是兩個(gè)范例組件及其 ?AdComponent
?接口:
import { Component, Input } from '@angular/core';
import { AdComponent } from './ad.component';
@Component({
template: `
<div class="job-ad">
<h4>{{data.headline}}</h4>
{{data.body}}
</div>
`
})
export class HeroJobAdComponent implements AdComponent {
@Input() data: any;
}
import { Component, Input } from '@angular/core';
import { AdComponent } from './ad.component';
@Component({
template: `
<div class="hero-profile">
<h3>Featured Hero Profile</h3>
<h4>{{data.name}}</h4>
<p>{{data.bio}}</p>
<strong>Hire this hero today!</strong>
</div>
`
})
export class HeroProfileComponent implements AdComponent {
@Input() data: any;
}
export interface AdComponent {
data: any;
}
最終的廣告欄是這樣的:
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: