angular2+创建宿主视图(动态组件)-欢迎使用zwight个人网站系统
×

angular2+创建宿主视图(动态组件)

    创建动态组件前先需要了解一个名词ViewRef,ViewRef表示一个angular视图,在angular中视图(View)是应用程序UI的基本构件。angular鼓励开发人员将UI看作是视图的组成,而不是独立的html标记树。

    Angular支持两种视图

  • Embedded Views which are linked to a Template(连接到模板的嵌入式视图)

    -----连接到模板的嵌入视图,在组件模板元素中添加模板(DOM元素、DOM元素组)

  • Host Views which are linked to a Component(连接到组建的宿主视图)

    -----连接到组件的嵌入视图,在组件元素中添加别的组件

    目前我们只讨论创建宿主视图。


Creating host view(创建宿主视图)

    当组件被动态实例化时,会创建宿主视图,使用ComponentFactoryResolver 可以动态的创建一个组件。

    在angular中每个组件都要被绑定到一个注入器(inject)的特定实例,因此我们在创建组件时传递当前的注入器实例,而且需要将动态实例化的组件添加到模块或托管组件的EnterComponents中。视图创建完毕后我们可以使用ViewContainer将其插入到DOM中。

ViewContainerRef

    表示一个容器,其中可以附加一个或多个视图。

    这里要提到的第一件事是,任何DOM元素都可以用作视图容器。有趣的是,Angular 在元素内部没有插入视图,而是在元素绑定到 ViewContainer 之后附加它们。这类似于 router-outlet 插入组件。

    通常,一个好的候选对象可以标记一个 ViewContainer 应该被创建的位置,它是 ng-container 元素。它是作为一个注释呈现的,因此它不会向DOM引入冗余的html元素。下面是一个 ViewContainer 的示例:

@Component({
    selector: 'sample',
    template: `
        <span>I am first span</span>
        <ng-container #vc></ng-container>        
        <span>I am last span</span>
    `
})export class SampleComponent implements AfterViewInit {
    @ViewChild("vc", {read: ViewContainerRef}) vc: ViewContainerRef;
    ngAfterViewInit(): void {
     // outputs `template bindings={}`
     console.log(this.vc.element.nativeElement.textContent);
    }
}

    正如其他DOM抽象一样, ViewContainer 被绑定到通过 element 属性访问的特定DOM元素。在这个例子中,它绑定到 ng-container 元素作为注释,因此输出是 template bindings={} 。

Manipulating views (操作视图)

    ViewContainer为操作视图提供了一个方便的api

class ViewContainerRef {
    ...clear() : void
    insert(viewRef: ViewRef, index?: number) : ViewRef
    get(index: number) : ViewRef
    indexOf(viewRef: ViewRef) : number
    detach(index?: number) : ViewRef
    move(viewRef: ViewRef, currentIndex: number) : ViewRef
}

    我们前面已经看到了如何从模板和组件手动创建两种视图。一旦我们有了视图,我们就可以使用insert方法将它 insert 到DOM中。

    ViewContainer还提供了自动创建视图的API

class ViewContainerRef {    element: ElementRef
    length: number    
    createComponent(componentFactory...): ComponentRef<C>    
    createEmbeddedView(templateRef...): EmbeddedViewRef<C>
    ...
}

下面是自动创建视图的例子

import { Component, ViewChild, ComponentFactoryResolver, Input, ComponentRef, OnInit, AfterViewInit } from "@angular/core";

@Component({
selector: 'modal-host',
templateUrl: './modal-host.component.html',
styleUrls: ['./modal-host.component.scss']
})
export class ModalHostComponent{

isShow: boolean = false;
@ViewChild('container') modalContentHost: ViewContainerRef;

constructor(
private componentFactoryResolver: ComponentFactoryResolver,
) { }
private _contentComponent: any;
@Input('content-data') contentData: any;
@Input('content-component') set contentComponent(value: any) {
this._contentComponent = value;
if (!!this._contentComponent) {
this.loadComponent();
} else {
this.clearComponent();
}
}
get contentComponent() {
return this._contentComponent;
}
private componentRef: ComponentRef<any>;

loadComponent() {
setTimeout(()=>{
this.isShow = true;
},10)
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(this._contentComponent);
this.modalContentHost.viewContainerRef.clear();
this.componentRef = this.modalContentHost.viewContainerRef.createComponent(componentFactory);
if (!!this.contentData) {
this.componentRef.instance.data = this.contentData;
}
}
clearComponent() {
if (!!this.modalContentHost) {
this.modalContentHost.viewContainerRef.clear();
}
this.isShow = false;
}
close() {

}

stopPropagation($event) {
$event.stopPropagation();
}
}

ngComponentOutlet

该指令类似于 ngTemplateOutlet,其不同之处在于它创建了一个宿主视图(实例化一个组件),而不是一个嵌入式视图,该指令在angular4+中开始出现。你可以这样使用:

<ng-container *ngComponentOutlet="ColorComponent"></ng-container>