在介绍 TemplateRef 前,我们先来了解一下 HTML 模板元素 - <template> 。模板元素是一种机制,允许包含加载页面时不渲染,但又可以随后通过 JavaScript 进行实例化的客户端内容。我们可以将模板视作为存储在页面上稍后使用的一小段内容。
在 HTML5 标准引入 template 模板元素之前,我们都是使用 <script> 标签进行客户端模板的定义,具体如下:
<script type="text/template"> <span>I am span in mock template</span> </script>
对于支持 HTML5 template 模板元素的浏览器,我们可以这样创建客户端模板:
<template> <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></div> <!-- Template --> <template> <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); } }
上述代码运行后的控制台的输出结果如下: