Angular2学习教程之TemplateRef和ViewContainerRef详解

网友投稿 501 2023-05-12


Angular2学习教程之TemplateRef和ViewContainerRef详解

TemplateRef

在介绍 TemplateRef 前,我们先来了解一下 HTML 模板元素 -

在 HTML5 标准引入 template 模板元素之前,我们都是使用

对于支持 HTML5 template 模板元素的浏览器,我们可以这样创建客户端模板:

I am span in template

下面我们来看一下 HTML5 template 模板元素的使用示例:

I am span in templatehttp://

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

HTML5 Template Element Demo

I am span in template

而当我们注释掉 tplContainer.appendChild(tplNode) 语句时,刷新浏览器后看到的是:

HTML5 Template Element Demo

这说明页面中

import {Component, TemplateRef, ViewChild, AfterViewInit} from '@angular/core';

@Component({

selector: 'my-app',

template: `

I am span in template

`,

})

export class AppComponent {

name: string = 'Semlinker';

@ViewChild('tpl')

tpl: TemplateRef;

ngAfterViewInit() {

console.dir(this.tpl);

}

}

上述代码运行后的控制台的输出结果如下:

从上图中,我们发现 @Component template 中定义的

TemplateRef_

// @angular/core/src/linker/template_ref.d.ts

export declare class TemplateRef_ extends TemplateRef {

private _parentView;

private _nodeIndex;

private _nativeElement;

constructor(_parentView: AppView, _nodeIndex: number, _nativeElement: any);

createEmbeddedView(context: C): EmbeddedViewRef;

elementRef: ElementRef;

}

TemplateRef

// @angular/core/src/linker/template_ref.d.ts

// 用于表示内嵌的template模板,能够用于创建内嵌视图(Embedded Views)

export declare abstract class TemplateRef {

elementRef: ElementRef;

abstract createEmbeddedView(context: C): EmbeddedViewRef;

}

(备注:抽象类与普通类的区别是抽象类有包含抽象方法,不能直接实例化抽象类,只能实例化该抽象类的子类)

我们已经知道

import {Component, TemplateRef, ViewChild, AfterViewInit} from '@angular/core';

@Component({

selector: 'my-app',

template: `

I am span in template

`,

})

export class AppComponent {

name: string = 'Semlinker';

@ViewChild('tpl')

tpl: TemplateRef;

ngAfterViewInit() {

let embeddedView = this.tpl.createEmbeddedView(null);

console.dir(embeddedView);

}

}

上述代码运行后的控制台的输出结果如下:

从图中我们可以知道,当调用 createEmbeddedView 方法后返回了 ViewRef_ 视图对象。该视图对象的 rootNodes 属性包含了

import { Component, TemplateRef, ViewChild, AfterViewInit } from '@angular/core';

@Component({

selector: 'my-app',

template: `

I am span in template {{name}}

`,

})

export class AppComponent {

name: string = 'Semlinker';

@ViewChild('tpl')

tpl: TemplateRef;

ngAfterViewInit() {

// 页面中的元素

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: `

I am span in template

`,

})

export class AppComponent {

name: string = 'Semlinker';

@ViewChild('tpl')

tplRef: TemplateRef;

@ViewChild('tpl', { read: ViewContainerRef })

tplVcRef: ViewContainerRef;

ngAfterViewInit() {

// console.dir(this.tplVcRef); (1)

this.tplVcRef.createEmbeddedView(this.tplRef);

}

}

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

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

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(templateRef: TemplateRef, context?: C,

index?: number): EmbeddedViewRef;

// 基 ComponentFactory创建组件视图

createComponent(componentFactory: ComponentFactory,

index?: number, injector?: Injector, projectableNodes?: any[][]): ComponentRef;

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

constructor(private injector: Injector,

private r: ComponentFactoryResolver) {

let factory = this.r.resolveComponentFactory(AppComponent);

let componentRef = factory.create(injector);

let view = componentRef.hostView;

}

2.Angular 2 Component 组件中定义的

因为

3.ViewRef 与 EmbeddedViewRef 之间有什么关系 ?

ViewRef 用于表示 Angular View(视图),视图是可视化的 UI 界面。EmbeddedViewRef 继承于 ViewRef,用于表示

ViewRef

// @angular/core/src/linker/view_ref.d.ts

export declare abstract class ViewRef {

destroyed: boolean;

abstract onDestroy(callback: Function): any;

}

EmbeddedViewRef

// @angular/core/src/linker/view_ref.d.ts

export declare abstract class EmbeddedViewRef extends ViewRef {

context: C;

rootNodes: any[]; // 保存

abstract destroy(): void; // 用于销毁视图

}

总结

Angular 2 中 TemplateRef 与 ViewContainerRef 的概念对于初学者来说会比较羞涩难懂,本文从基本的 HTML 5

好了,以上就是这篇文章的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Angular 2.x学习教程之结构指令详解
下一篇:很棒的vue弹窗组件
相关文章

 发表评论

暂时没有评论,来抢沙发吧~