Angular2学习教程之TemplateRef和ViewContainerRef详解(2)

从图中我们可以知道,当调用 createEmbeddedView 方法后返回了 ViewRef_ 视图对象。该视图对象的 rootNodes 属性包含了 <template> 模板中的内容。在上面的例子中,我们知道了 TemplateRef 实例对象中的 elementRef 属性封装了我们的 comment 元素,那么我们可以通过 insertBefore 方法来创建我们模板中定义的内容。

import { Component, TemplateRef, ViewChild, AfterViewInit } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>Welcome to Angular World</h1> <template #tpl> <span>I am span in template {{name}}</span> </template> `, }) export class AppComponent { name: string = 'Semlinker'; @ViewChild('tpl') tpl: TemplateRef<any>; ngAfterViewInit() { // 页面中的<!--template bindings={}-->元素 let commentElement = this.tpl.elementRef.nativeElement; // 创建内嵌视图 let embeddedView = this.tpl.createEmbeddedView(null); // 动态添加子节点 embeddedView.rootNodes.forEach((node) => { commentElement.parentNode .insertBefore(node, commentElement.nextSibling); }); } }

成功运行上面的代码后,在浏览器中我们会看到以下内容:

Welcome to Angular World I am span in template

现在我们来回顾一下,上面的处理步骤:

创建内嵌视图(embedded view)

遍历内嵌视图中的 rootNodes,动态的插入 node

虽然我们已经成功的显示出 template 模板元素中的内容,但发现整个流程还是太复杂了,那有没有简单地方式呢 ?是时候介绍本文中第二个主角 - ViewContainerRef。

ViewContainerRef

我们先来检验一下它的能力,然后再来好好地分析它。具体示例如下:

import { Component, TemplateRef, ViewChild, ViewContainerRef, AfterViewInit } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>Welcome to Angular World</h1> <template #tpl> <span>I am span in template</span> </template> `, }) export class AppComponent { name: string = 'Semlinker'; @ViewChild('tpl') tplRef: TemplateRef<any>; @ViewChild('tpl', { read: ViewContainerRef }) tplVcRef: ViewContainerRef; ngAfterViewInit() { // console.dir(this.tplVcRef); (1) this.tplVcRef.createEmbeddedView(this.tplRef); } }

移除上面代码中的注释,即可在控制台看到以下的输出信息:

Angular2学习教程之TemplateRef和ViewContainerRef详解

而在浏览器中我们会看到以下内容:

Welcome to Angular World I am span in template

接下来我们来看一下 ViewContainerRef_ 类:

// @angular/core/src/linker/view_container_ref.d.ts // 用于表示一个视图容器,可添加一个或多个视图 export declare class ViewContainerRef_ implements ViewContainerRef { ... length: number; // 返回视图容器中已存在的视图个数 element: ElementRef; injector: Injector; parentInjector: Injector; // 基于TemplateRef创建内嵌视图,并自动添加到视图容器中,可通过index设置 // 视图添加的位置 createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, index?: number): EmbeddedViewRef<C>; // 基 ComponentFactory创建组件视图 createComponent<C>(componentFactory: ComponentFactory<C>, index?: number, injector?: Injector, projectableNodes?: any[][]): ComponentRef<C>; insert(viewRef: ViewRef, index?: number): ViewRef; move(viewRef: ViewRef, currentIndex: number): ViewRef; indexOf(viewRef: ViewRef): number; remove(index?: number): void; detach(index?: number): ViewRef; clear(): void; }

通过源码我们可以知道通过 ViewContainerRef_ 实例,我们可以方便地操作视图,也可以方便地基于 TemplateRef 创建视图。现在我们来总结一下 TemplateRef 与 ViewContainerRef。

TemplateRef:用于表示内嵌的 template 模板元素,通过 TemplateRef 实例,我们可以方便创建内嵌视图(Embedded Views),且可以轻松地访问到通过 ElementRef 封装后的 nativeElement。需要注意的是组件视图中的 template 模板元素,经过渲染后会被替换成 comment 元素。

ViewContainerRef:用于表示一个视图容器,可添加一个或多个视图。通过 ViewContainerRef 实例,我们可以基于 TemplateRef 实例创建内嵌视图,并能指定内嵌视图的插入位置,也可以方便对视图容器中已有的视图进行管理。简而言之,ViewContainerRef 的主要作用是创建和管理内嵌视图或组件视图。

我有话说

1.Angular 2 支持的 View(视图) 类型有哪几种 ?

Embedded Views - Template 模板元素

Host Views - Component 组件

1.1 如何创建 Embedded View

ngAfterViewInit() { let view = this.tpl.createEmbeddedView(null); }

1.2 如何创建 Host View

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wysyfp.html