Angular2学习教程之TemplateRef和ViewContainerRef详解
发布时间 - 2026-01-11 01:18:44 点击率:次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 指令
# 我们可以
# 内嵌
# 的是
# 先来
# 抽象类
# 多个
# 客户端
# 替换成
# 器中
# 这篇文章
# 后会
# 图中
# 移除
# 都是
# 是一种
# 好了
# 第一个
# 子类
# 我有
# 遍历
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何在橙子建站中快速调整背景颜色?
Laravel怎么在Controller之外的地方验证数据
Laravel如何配置中间件Middleware_Laravel自定义中间件拦截请求与权限校验【步骤】
Laravel如何清理系统缓存命令_Laravel清除路由配置及视图缓存的方法【总结】
如何在搬瓦工VPS快速搭建网站?
打开php文件提示内存不足_怎么调整php内存限制【解决方案】
如何在HTML表单中获取用户输入并结合JavaScript动态控制复利计算循环
Windows Hello人脸识别突然无法使用
Laravel如何处理异常和错误?(Handler示例)
Laravel如何生成API文档?(Swagger/OpenAPI教程)
EditPlus中的正则表达式实战(6)
如何快速配置高效服务器建站软件?
Laravel如何安装使用Debugbar工具栏_Laravel性能调试与SQL监控插件【步骤】
小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?
Android自定义listview布局实现上拉加载下拉刷新功能
音响网站制作视频教程,隆霸音响官方网站?
Laravel如何构建RESTful API_Laravel标准化API接口开发指南
如何用搬瓦工VPS快速搭建个人网站?
如何快速搭建自助建站会员专属系统?
html如何与html链接_实现多个HTML页面互相链接【互相】
活动邀请函制作网站有哪些,活动邀请函文案?
Laravel如何处理跨站请求伪造(CSRF)保护_Laravel表单安全机制与令牌校验
zabbix利用python脚本发送报警邮件的方法
最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?
深圳网站制作公司好吗,在深圳找工作哪个网站最好啊?
Laravel Pest测试框架怎么用_从PHPUnit转向Pest的Laravel测试教程
高防服务器租用如何选择配置与防御等级?
公司门户网站制作流程,华为官网怎么做?
如何挑选优质建站一级代理提升网站排名?
Python自动化办公教程_ExcelWordPDF批量处理案例
Laravel用户密码怎么加密_Laravel Hash门面使用教程
,交易猫的商品怎么发布到网站上去?
如何基于云服务器快速搭建个人网站?
Laravel如何实现本地化和多语言支持?(i18n教程)
Win11怎样安装网易有道词典_Win11安装词典教程【步骤】
如何用PHP工具快速搭建高效网站?
零基础网站服务器架设实战:轻量应用与域名解析配置指南
Laravel安装步骤详细教程_Laravel环境搭建指南
如何正确下载安装西数主机建站助手?
如何用西部建站助手快速创建专业网站?
Laravel如何使用Facades(门面)及其工作原理_Laravel门面模式与底层机制
Laravel如何操作JSON类型的数据库字段?(Eloquent示例)
使用C语言编写圣诞表白程序
HTML5段落标签p和br怎么选_文本排版常用标签对比【解答】
Laravel辅助函数有哪些_Laravel Helpers常用助手函数大全
移动端手机网站制作软件,掌上时代,移动端网站的谷歌SEO该如何做?
Laravel怎么返回JSON格式数据_Laravel API资源Response响应格式化【技巧】
HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】
ChatGPT怎么生成Excel公式_ChatGPT公式生成方法【指南】
edge浏览器无法安装扩展 edge浏览器插件安装失败【解决方法】

