全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

Angular2学习教程之TemplateRef和ViewContainerRef详解

TemplateRef

在介绍 TemplateRef 前,我们先来了解一下 HTML 模板元素 - <template> 。模板元素是一种机制,允许包含加载页面时不渲染,但又可以随后通过 JavaScript 进行实例化的客户端内容。我们可以将模板视作为存储在页面上稍后使用的一小段内容。

在 HTML5 标准引入 template 模板元素之前,我们都是使用 <script> 标签进行客户端模板的定义,具体如下:

<script id="tpl-mock" type="text/template">
 <span>I am span in mock template</span>
</script>

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

<template id="tpl">
 <span>I am span in template</span>
</template>

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

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"> <title>HTML5 Template Element Demo</title></head>
<body>
<h4>HTML5 Template Element Demo</h4>
<!-- Template Container -->
<div class="tpl-container"></div>
<!-- Template -->
<template id="tpl">
 <span>I am span in template</span>
</template>
<!-- Script -->
<script type="text/javascript">
 (function renderTpl() {
 if ('content' in document.createElement('template')) {
 var tpl = document.querySelector('#tpl');
 var tplContainer = document.querySelector('.tpl-container');
 var tplNode = document.importNode(tpl.content, true);
 tplContainer.appendChild(tplNode); 
 } else {
 throw new Error("Current browser doesn't support template element");
 }
 })();
</script>
</body>
</html>

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

HTML5 Template Element Demo

I am span in template

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

HTML5 Template Element Demo

这说明页面中 <template> 模板元素中的内容,如果没有进行处理对用户来说是不可见的。Angular 2 中,<template> 模板元素主要应用在结构指令中,接下来我们先来介绍一下本文中的第一个主角 - TemplateRef:

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</span>
 </template>
 `,
})
export class AppComponent {
 name: string = 'Semlinker';

 @ViewChild('tpl')
 tpl: TemplateRef<any>;

 ngAfterViewInit() {
 console.dir(this.tpl);
 }
}

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

从上图中,我们发现 @Component template 中定义的 <template> 模板元素,渲染后被替换成 comment 元素,其内容为 "template bindings={}" 。此外我们通过 @ViewChild 获取的模板元素,是 TemplateRef_ 类的实例,接下来我们来研究一下 TemplateRef_ 类:

TemplateRef_

// @angular/core/src/linker/template_ref.d.ts
export declare class TemplateRef_<C> extends TemplateRef<C> {
 private _parentView;
 private _nodeIndex;
 private _nativeElement;
 constructor(_parentView: AppView<any>, _nodeIndex: number, _nativeElement: any);
 createEmbeddedView(context: C): EmbeddedViewRef<C>;
 elementRef: ElementRef;
}

TemplateRef

// @angular/core/src/linker/template_ref.d.ts
// 用于表示内嵌的template模板,能够用于创建内嵌视图(Embedded Views)
export declare abstract class TemplateRef<C> {
 elementRef: ElementRef;
 abstract createEmbeddedView(context: C): EmbeddedViewRef<C>;
}

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

我们已经知道 <template> 模板元素,渲染后被替换成 comment 元素,那么应该如何显示我们模板中定义的内容呢 ?我们注意到了 TemplateRef 抽象类中定义的 createEmbeddedView抽象方法,该方法的返回值是 EmbeddedViewRef 对象。那好我们马上来试一下:

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</span>
 </template>
 `,
})
export class AppComponent {
 name: string = 'Semlinker';

 @ViewChild('tpl')
 tpl: TemplateRef<any>;

 ngAfterViewInit() {
 let embeddedView = this.tpl.createEmbeddedView(null);
 console.dir(embeddedView);
 }
}

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

从图中我们可以知道,当调用 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);
 }
}

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

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

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

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 组件中定义的 <template> 模板元素为什么渲染后会被移除 ?

因为 <template> 模板元素,已经被 Angular 2 解析并封装成 TemplateRef 实例,通过 TemplateRef 实例,我们可以方便地创建内嵌视图(Embedded View),我们不需要像开篇中的例子那样,手动操作 <template> 模板元素。

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

ViewRef 用于表示 Angular View(视图),视图是可视化的 UI 界面。EmbeddedViewRef 继承于 ViewRef,用于表示 <template> 模板元素中定义的 UI 元素。

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<C> extends ViewRef {
 context: C;
 rootNodes: any[]; // 保存<template>模板中定义的元素
 abstract destroy(): void; // 用于销毁视图
}

总结

Angular 2 中 TemplateRef 与 ViewContainerRef 的概念对于初学者来说会比较羞涩难懂,本文从基本的 HTML 5 <template> 模板元素开始,介绍了如何操作和应用页面中定义的模板。然后通过实例介绍了 Angular 2 中 TemplateRef 和 ViewContainerRef 的定义和作用。希望通过这篇文章,读者能更好的理解 TemplateRef 与 ViewContainerRef。

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


# angular2  # templateref  # template  # 详解Angular 4.x NgTemplateOutlet  # Angular.JS中的指令引用template与指令当做属性详解  # AngularJS延迟加载html template  # Angular中的ng-template及angular 使用ngTemplateOutlet 指令  # 我们可以  # 内嵌  # 的是  # 先来  # 抽象类  # 多个  # 客户端  # 替换成  # 器中  # 这篇文章  # 后会  # 图中  # 移除  # 都是  # 是一种  # 好了  # 第一个  # 子类  # 我有  # 遍历 


相关文章: jQuery 常见小例汇总  成都网站制作价格表,现在成都广电的单独网络宽带有多少的,资费是什么情况呢?  清单制作人网站有哪些,近日“兴风作浪的姑奶奶”引起很多人的关注这是什么事情?  C#如何序列化对象为XML XmlSerializer用法  如何配置支付宝与微信支付功能?  家庭服务器如何搭建个人网站?  网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?  建站之星如何实现网站加密操作?  标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?  盐城做公司网站,江苏电子版退休证办理流程?  建站DNS解析失败?如何正确配置域名服务器?  建站之星安装提示数据库无法连接如何解决?  上海网站制作开发公司,上海买房比较好的网站有哪些?  昆明高端网站制作公司,昆明公租房申请网上登录入口?  php能控制zigbee模块吗_php通过串口与cc2530 zigbee通信【介绍】  如何在建站宝盒中设置产品搜索功能?  相册网站制作软件,图片上的网址怎么复制?  Swift开发中switch语句值绑定模式  定制建站是什么?如何实现个性化需求?  建站之星备案是否影响网站上线时间?  怎么用手机制作网站链接,dw怎么把手机适应页面变成网页?  如何选择PHP开源工具快速搭建网站?  早安海报制作网站推荐大全,企业早安海报怎么每天更换?  高端建站如何打造兼具美学与转化的品牌官网?  如何用IIS7快速搭建并优化网站站点?  已有域名能否直接搭建网站?    移民网站制作流程,怎么看加拿大移民官网?  C#如何使用XPathNavigator高效查询XML  建站主机系统SEO优化与智能配置核心关键词操作指南  如何在建站主机中优化服务器配置?  邀请函制作网站有哪些,有没有做年会邀请函的网站啊?在线制作,模板很多的那种?  网站制作费用多少钱,一个网站的运营,需要哪些费用?  最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?  电脑免费海报制作网站推荐,招聘海报哪个网站多?  如何快速搭建高效香港服务器网站?  大学网站设计制作软件有哪些,如何将网站制作成自己app?  Swift中循环语句中的转移语句 break 和 continue  如何有效防御Web建站篡改攻击?  建站中国必看指南:CMS建站系统+手机网站搭建核心技巧解析  网站制作公司,橙子建站是合法的吗?  c# 在ASP.NET Core中管理和取消后台任务  常州企业网站制作公司,全国继续教育网怎么登录?  制作网站的基本流程,设计网站的软件是什么?  如何在Windows 2008云服务器安全搭建网站?  宝盒自助建站智能生成技巧:SEO优化与关键词设置指南  如何快速建站并高效导出源代码?  佛山企业网站制作公司有哪些,沟通100网上服务官网?  如何在IIS管理器中快速创建并配置网站?  建站org新手必看:2024最新搭建流程与模板选择技巧 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。