www.angular.cn中文笔记和翻译 - Christian-Yang/Translate-and-save GitHub Wiki
烹饪宝典:动态组件加载器
https://www.angular.cn/docs/ts/latest/cookbook/dynamic-component-loader.html
Component templates are not always fixed. An application may need to load new components at runtime.
组件模板并不总是固定的。 应用程序可能需要在运行时加载新的组件。
This cookbook shows you how to use ComponentFactoryResolver(组件工厂解析器) to add components dynamically.
本食谱介绍如何使用ComponentFactoryResolver动态添加组件。
Dynamic component loading
动态组件加载
The following example shows how to build a dynamic ad banner.
以下示例显示如何构建动态广告横幅。
The hero agency is planning an ad campaign with several different ads cycling through the banner. New ad components are added frequently by several different teams. This makes it impractical to use a template with a static component structure.
英雄机构正在计划一个广告活动,其中包含几个不同的广告。 新的广告组件经常被几个不同的团队添加。 这使得使用具有静态组件结构的模板变得不切实际。
Instead, you need a way to load a new component without a fixed reference to the component in the ad banner's template.
相反,您需要一种加载新组件的方法,而无需对广告横幅模板中的组件进行固定的引用。
Angular comes with its own API for loading components dynamically.Angular自带了用于动态加载组件的API。
The directive
指令
Before you can add components you have to define an anchor point to tell Angular where to insert components.
在添加组件之前,必须定义一个定位点,以便指定Angular在哪里插入组件。
The ad banner uses a helper directive called AdDirective to mark valid insertion points in the template.
广告横幅使用称为AdDirective的辅助程序指令来标记模板中的有效插入点。
src/app/ad.directive.ts
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[ad-host]',
})
export class AdDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
AdDirective injects ViewContainerRef to gain access to the view container of the element that will host the dynamically added component.
AdDirective注入ViewContainerRef以访问将承载动态添加的组件的元素的视图容器。
In the @Directive decorator, notice the selector name, ad-host; that's what you use to apply the directive to the element. The next section shows you how.
在@Directive装饰器中,注意选择器名称,ad-host; 这是您将元素应用于该元素的方法。 下一节将向您展示如何。
Loading components
加载组件
Most of the ad banner implementation is in ad-banner.component.ts. To keep things simple in this example, the HTML is in the @Component decorator's template property as a template string.
大多数广告横幅的执行都在ad-banner.component.ts中。 为了在这个例子中保持简单,HTML在@Component装饰器的模板属性中作为模板字符串。
The element is where you apply the directive you just made. To apply the AdDirective, recall the selector from ad.directive.ts, ad-host. Apply that to without the square brackets. Now Angular knows where to dynamically load components.
元素是您应用刚刚创建的伪指令的地方。 要应用AdDirective,请从ad.directive.ts,ad-host调用选择器。 将其应用于而不使用方括号。 现在Angular知道在哪里动态加载组件。
ad-banner.component.ts文件内容如下:
template: `
<div class="ad-banner">
<h3>Advertisements</h3>
<ng-template ad-host></ng-template>
</div>
`
```<ng-template>```元素是动态组件的不错选择,因为它不会渲染任何额外的输出。
Resolving components 解析组件 Take a closer look at the methods in ad-banner.component.ts.
仔细观察ad-banner.component.ts中的方法。
AdBannerComponent takes an array of AdItem objects as input, which ultimately comes from AdService. AdItem objects specify the type of component to load and any data to bind to the component.AdService returns the actual ads making up the ad campaign.
AdBannerComponent将AdItem对象的数组作为输入,最终来自AdService。 AdItem对象指定要加载的组件类型以及绑定到组件的任何数据.AdService返回构成广告系列的实际广告。
Passing an array of components to AdBannerComponent allows for a dynamic list of ads without static elements in the template.
将一组组件传递到AdBannerComponent允许在模板中的静态元素的动态列表。
With its getAds() method, AdBannerComponent cycles through the array of AdItems and loads a new component every 3 seconds by calling loadComponent().
使用其getAds()方法,AdBannerComponent循环遍历AdItem数组,并通过调用loadComponent()每3秒加载一个新的组件。
ad-banner.component.ts.文件内容如下:
export class AdBannerComponent implements AfterViewInit, OnDestroy {
@Input() ads: AdItem[];
currentAddIndex: number = -1;
@ViewChild(AdDirective) adHost: AdDirective;
subscription: any;
interval: any;
constructor(private _componentFactoryResolver: ComponentFactoryResolver) { }
ngAfterViewInit() {
this.loadComponent();
this.getAds();
}
ngOnDestroy() {
clearInterval(this.interval);
}
loadComponent() {
this.currentAddIndex = (this.currentAddIndex + 1) % this.ads.length;
let adItem = this.ads[this.currentAddIndex];
let componentFactory = this._componentFactoryResolver.resolveComponentFactory(adItem.component);
let viewContainerRef = this.adHost.viewContainerRef;
viewContainerRef.clear();
let componentRef = viewContainerRef.createComponent(componentFactory);
(<AdComponent>componentRef.instance).data = adItem.data;
}
getAds() {
this.interval = setInterval(() => {
this.loadComponent();
}, 3000);
}
}
The loadComponent() method is doing a lot of the heavy lifting here. Take it step by step. First, it picks an ad.
loadComponent()方法在这里做了很多重的工作。 一步步走。 首先,它选择一个广告。
How loadComponent() chooses an ad
loadComponent()如何选择一个广告
The loadComponent() method chooses an ad using some math.
loadComponent()方法使用一些数学来选择一个广告。
First, it sets the currentAddIndex by taking whatever it currently is plus one, dividing that by the length of the AdItem array, and using the remainder as the new currentAddIndex value. Then, it uses that value to select an adItem from the array.
首先,它将currentAddIndex通过取其当前加1加上一个,除以AdItem数组的长度,并将余数作为新的currentAddIndex值。 然后,它使用该值从数组
中选择一个adItem。
After loadComponent() selects an ad, it uses ComponentFactoryResolver to resolve a ComponentFactory for each specific component. The ComponentFactory then creates an instance of each component.
在loadComponent()选择一个广告之后,它使用ComponentFactoryResolver解决每个特定组件的ComponentFactory。 然后,ComponentFactory创建每个组件的一个实例。
Next, you're targeting the viewContainerRef that exists on this specific instance of the component. How do you know it's this specific instance? Because it's referring to adHost and adHost is the directive you set up earlier to tell Angular where to insert dynamic components.
接下来,您将针对组件的此特定实例上存在的viewContainerRef。 你怎么知道这个具体的例子? 因为它是指adHost和adHost是您早先设置的指令,以指示Angular在哪里插入动态组件。
As you may recall, AdDirective injects ViewContainerRef into its constructor. This is how the directive accesses the element that you want to use to host the dynamic component.
您可能还记得,AdDirective将ViewContainerRef注入到其构造函数中。 这是指令访问要用于托管动态组件的元素。
To add the component to the template, you call createComponent() on ViewContainerRef.
要将组件添加到模板中,请在ViewContainerRef上调用createComponent()。
The createComponent() method returns a reference to the loaded component. Use that reference to interact with the component by assigning to its properties or calling its methods.
createComponent()方法返回对加载组件的引用。 使用该引用通过分配给其属性或调用其方法与组件进行交互。
SELECTOR REFERENCES选择引用
Generally, the Angular compiler generates a ComponentFactory for any component referenced in a template. However, there are no selector references in the templates for dynamically loaded components since they load at runtime.
通常,Angular编译器为模板中引用的任何组件生成一个ComponentFactory。 但是,动态加载组件的模板中没有选择器引用,因为它们在运行时加载。
To ensure that the compiler still generates a factory, add dynamically loaded components to the NgModule's entryComponents array:
为了确保编译器仍然生成工厂,将动态加载的组件添加到NgModule的entryComponents数组中: