【问题标题】:What is the difference between createEmbeddedView and createComponent?createEmbeddedView 和 createComponent 有什么区别?
【发布时间】:2017-09-21 08:15:28
【问题描述】:

我对@9​​87654321@ 和createComponent 的用例感到困惑,即何时使用哪一个。

请提出一些案例,说明在“动态创建场景”中使用它们的合适设置。

【问题讨论】:

    标签: angular


    【解决方案1】:

    请参阅this workshop on DOM manipulation 或阅读Working with DOM in Angular: unexpected consequences and optimization techniques,我会通过示例解释差异。

    这两种方法都用于向组件视图 (DOM) 动态添加内容。此内容可以是模板或基于组件。在 Angular 中,我们通常使用ViewContainerRef 来操作 DOM。并且这两种方法都可以使用:

    class ViewContainerRef {
        ...
        createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, index?: number): EmbeddedViewRef<C>
        createComponent<C>(componentFactory: ComponentFactory<C>, index?: number, injector?: Injector, projectableNodes?: any[][], ngModule?: NgModuleRef<any>): ComponentRef<C>
    }
    

    要了解有关操作 DOM 的更多信息,请阅读 Exploring Angular DOM manipulation techniques using ViewContainerRef

    createEmbeddedView

    它用于使用TemplateRef 创建视图。 TemplateRef 由 Angular 编译器在组件 html 中遇到 ng-template 标签时创建。 使用此方法创建的视图称为embedded view

    import { VERSION, Component, ViewChild, TemplateRef, ViewContainerRef } from '@angular/core';
    
    @Component({
      selector: 'my-app',
      template: `
          <ng-container #vc></ng-container>
          <ng-template #tpl>
              <h1>Hello, {{name}}</h1>
          </ng-template>
      `,
      styles: ['']
    })
    export class AppComponent {
      name = `Angular! v${VERSION.full}`;
    
      @ViewChild('tpl', {read: TemplateRef}) tpl: TemplateRef<any>;
      @ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;
    
      ngOnInit() {
        this.vc.createEmbeddedView(this.tpl);
      }
    }
    

    Stackblitz demo

    *ngIf*ngFor 等所有结构指令都使用这种方法,因为它们都是包装 ng-template。例如,*ngIf 的代码:

    <div *ngIf="data">{{name}}</div>
    

    变成了

    <ng-template ngIf="data">
       <div>{{name}}</div>
    

    ngIf 指令在内部使用createEmbeddedView

    @Directive({selector: '[ngIf]'})
    export class NgIf {
        private _updateView() {
           ...
           if (this._thenTemplateRef) {
               this._thenViewRef =
                   this._viewContainer.createEmbeddedView(this._thenTemplateRef, this._context);
    

    创建组件

    它用于使用ComponentFactory 创建视图。当您在模块的bootstrap 属性中指定组件时,Angular 编译器会创建它,因此编译器会为其生成工厂。使用此方法创建的视图称为hostview

    import { Component, ViewContainerRef, ComponentFactoryResolver, NgZone, VERSION, ViewChild } from '@angular/core';
    
    @Component({
      selector: 'hello',
      template: `<h1>Hello Component!</h1>`,
      styles: [``]
    })
    export class HelloComponent  {}
    
    @Component({
      selector: 'my-app',
      template: `
          <ng-container #vc></ng-container>
      `,
      styles: ['']
    })
    export class AppComponent {
    
      @ViewChild('vc', {read:ViewContainerRef}) vc: ViewContainerRef;
    
      constructor(private resolver: ComponentFactoryResolver) {}
    
      ngOnInit() {
        const factory = this.resolver.resolveComponentFactory(HelloComponent);
        this.vc.createComponent(factory);
      }
    }
    

    Stackblitz demo.

    要详细了解主机视图和嵌入式视图之间的区别,请阅读What is the difference between a view, a host view and an embedded view

    【讨论】:

    • 感谢@AngularInDepth.com 的回复。我按照您的链接了解“主机视图和嵌入式视图”之间的区别,现在我的理解是嵌入式视图适合创建动态 presentation 视图。但是,对于一个智能组件,它可以做的不仅仅是显示数据,createComponent 是要走的路。我说得对吗?
    • @Blaze,不客气。好吧,我想这是看待它的一种方式。由于嵌入式视图是从ng-template 创建的,并且没有与它们相关联的类而不是组件,因此确实没有太多逻辑可以放在embedded view 中。但是,我会说大多数嵌入式视图用于可重用的演示文稿。所有结构指令都使用ng-template。我会在答案中添加一点
    • 一个问题,ViewContainerRef#createComponent被调用后,能否保证组件必须在DOM中?
    • @Chao,一旦方法返回,它就在 DOM 中。
    • 我认为自从上次更新此答案以来,深度角度已经改变了家。 @MaxKoretskyi 您能否将 URL 更新为:indepth.dev/posts/1134/…
    猜你喜欢
    • 2010-10-02
    • 2011-12-12
    • 2010-09-16
    • 2012-03-14
    • 2012-02-06
    • 2011-02-25
    • 2011-11-22
    • 2015-03-26
    • 2013-08-19
    相关资源
    最近更新 更多