angular之ng-template模板加载


Posted in Javascript onNovember 09, 2017

本文介绍了angular之ng-template模板加载,分享给大家,具体如下:

html5中的template

template标签的含义:HTML <template>元素是一种用于保存客户端内容的机制,该内容在页面加载时是不可见的,但可以在运行时使用JavaScript进行实例化,可以将一个模板视为正在被存储以供随后在文档中使用的一个内容片段。

angular之ng-template模板加载

属性

此元素仅包含全局属性和只读的 content 属性,通过content 可以读取模板内容,而且可以通过判断 content 属性是否存在来判断浏览器是否支持 <template> 元素。

示例

html

<table id="producttable">
 <thead>
  <tr>
   <td>UPC_Code</td>
   <td>Product_Name</td>
  </tr>
 </thead>
 <tbody>
  <!-- 现有数据可以可选地包括在这里 -->
 </tbody>
</table>

<template id="productrow">
 <tr>
  <td class="record"></td>
  <td></td>
 </tr>
</template>

js

// 通过检查来测试浏览器是否支持HTML模板元素 
// 用于保存模板元素的内容属性。
if ('content' in document.createElement('template')) {

 // 使用现有的HTML tbody实例化表和该行与模板
 let t = document.querySelector('#productrow'),
 td = t.content.querySelectorAll("td");
 td[0].textContent = "1235646565";
 td[1].textContent = "Stuff";

 // 克隆新行并将其插入表中
 let tb = document.getElementsByTagName("tbody");
 let clone = document.importNode(t.content, true);
 tb[0].appendChild(clone);
 
 // 创建一个新行
 td[0].textContent = "0384928528";
 td[1].textContent = "Acme Kidney Beans";

 // 克隆新行并将其插入表中
 let clone2 = document.importNode(t.content, true);
 tb[0].appendChild(clone2);

} else {
 // 找到另一种方法来添加行到表,因为不支持HTML模板元素。
}

代码运行后,结果将是一个包含(由 JavaScript 生成)两个新行的 HTML 表格:

UPC_Code  Product_Name
1235646565 Stuff
0384928528 Acme Kidney Beans

注释掉 tb[0].appendChild(clone);和tb[0].appendChild(clone2);,运行代码,只会看到:
UPC_Code Product_Name

说明template元素中的内容如果不经过处理,浏览器是不会渲染的。

angular中的ng-template

<ng-template>是一个 Angular 元素,它永远不会直接显示出来。在渲染视图之前,Angular 会把<ng-template>及其内容替换为一个注释。

以ngIf为例:

angular之ng-template模板加载

<ng-template> 模板元素与html5的template元素一样,需要被特殊处理后才能渲染。ng主要是通过类TemplateRef和ViewContainerRef实现的。

通过阅读ngIf源码学习如何运用<ng-template>

在使用ngIf 指令时我们并未发现ng-template的身影,这是因为"*"(星号)语法糖的原因,这个简写方法是一个微语法,而不是通常的模板表达式, Angular会解开这个语法糖,变成一个<ng-template>标记,包裹着宿主元素及其子元素。

<div *ngIf="hero" >{{hero.name}}</div>

会被解析为

<ng-template [ngIf]="hero">
 <div>{{hero.name}}</div>
</ng-template>`

看下ngIf源码

import {Directive, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef} from '@angular/core';
@Directive({selector: '[ngIf]'})
export class NgIf {
 private _context: NgIfContext = new NgIfContext();
 private _thenTemplateRef: TemplateRef<NgIfContext>|null = null;
 private _elseTemplateRef: TemplateRef<NgIfContext>|null = null;
 private _thenViewRef: EmbeddedViewRef<NgIfContext>|null = null;
 private _elseViewRef: EmbeddedViewRef<NgIfContext>|null = null;

 constructor(private _viewContainer: ViewContainerRef, templateRef: TemplateRef<NgIfContext>) {
  this._thenTemplateRef = templateRef;
 }

 @Input()
 set ngIf(condition: any) {
  this._context.$implicit = this._context.ngIf = condition;
  this._updateView();
 }

 @Input()
 set ngIfThen(templateRef: TemplateRef<NgIfContext>) {
  this._thenTemplateRef = templateRef;
  this._thenViewRef = null; // clear previous view if any.
  this._updateView();
 }

 @Input()
 set ngIfElse(templateRef: TemplateRef<NgIfContext>) {
  this._elseTemplateRef = templateRef;
  this._elseViewRef = null; // clear previous view if any.
  this._updateView();
 }

 private _updateView() {
  if (this._context.$implicit) {
   if (!this._thenViewRef) {
    this._viewContainer.clear();
    this._elseViewRef = null;
    if (this._thenTemplateRef) {
     this._thenViewRef =
       this._viewContainer.createEmbeddedView(this._thenTemplateRef, this._context);
    }
   }
  } else {
   if (!this._elseViewRef) {
    this._viewContainer.clear();
    this._thenViewRef = null;
    if (this._elseTemplateRef) {
     this._elseViewRef =
       this._viewContainer.createEmbeddedView(this._elseTemplateRef, this._context);
    }
   }
  }
 }
}

export class NgIfContext {
 public $implicit: any = null;
 public ngIf: any = null;
}

ngIf的源码并不难,它的核心就在于_updateView函数,它主要通过ViewContainerRef的createEmbeddedView和clear方法来实现模板TemplateRef的呈现和清除(先不关注当中的then和else等的具体实现)。它使用TemplateRef取得<ng-template>的内容,并通过ViewContainerRef来访问这个视图容器。

TemplateRef

TemplateRef 实例用于表示模板对象,TemplateRef 抽象类的定义如下:

abstract get elementRef(): ElementRef;
 abstract createEmbeddedView(context: C): EmbeddedViewRef<C>;
}

在指令中通过依赖注入TemplateRef可以直接拿到ng-tempalte的TemplateRef,但是在component组件中我们则需要使用viewChild

<ng-template #tptest>
 <span>template test</span>
</ng-template>

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

ViewContainerRef

ViewContainerRef 实例提供了 createEmbeddedView() 方法,该方法接收 TemplateRef 对象作为参数,并将模板中的内容作为容器 (comment 元素) 的兄弟元素,插入到页面中。

export abstract class ViewContainerRef {
  /*基于TemplateRef对象创建Embedded View(内嵌视图),然后根据`index`指定的值,插入到容器中。 
  如果没有指定`index`的值,新创建的视图将作为容器中的最后一个视图插入。*/ 
 abstract createEmbeddedView<C>(
   templateRef: TemplateRef<C>, //内嵌视图
   context?: C, index?: number): // 创建上下文
   EmbeddedViewRef<C>;
}

createEmbeddedView:context

创建Template 自身 Context 的属性,以ngFor为例:
查看ngFor Context源码:

export class NgForOfContext<T> {
 constructor(
   public $implicit: T, public ngForOf: NgIterable<T>, public index: number,
   public count: number) {}

 get first(): boolean { return this.index === 0; }

 get last(): boolean { return this.index === this.count - 1; }

 get even(): boolean { return this.index % 2 === 0; }

 get odd(): boolean { return !this.even; }
}
<div *ngFor="let hero of heroes; let i=index; let odd=odd">
 ({{i}}) {{hero.name}}
</div>


解析后:

<ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" >
 <div>({{i}}) {{hero.name}}</div>
</ng-template>

从例子中可以看到,通过let-i let-odd可以获取到Template的context,这是angular提供的一种语法。因为在 Angular中是没有作用域继承的,所以在模版中无法隐式实现两个无关数据源。一个简单的实现方案就是:一个显式、一个隐式。由于ng-template tag 是写在某个 Component 的 template属性中的,所以在 ng-template tag 之下的部分当然能访问的也只有 Component 作为 Context 提供的属性,从而保持行为的一致性,而如果需要访问到 Template 的 Context,我们就需要使用额外的引入语法。比如 let-i="index",就是把 Template Context 中的 index属性引入到当前的 Component Context 中并赋予别名 i,这样,我们就能够使用 i 这个标识符来访问到 Template Context 中的属性了,并且仍然保持了行为的一致性和作用域的独立性。

模板输入变量是这样一种变量,你可以在单个实例的模板中引用它的值。 这个例子中有好几个模板输入变量:hero、i和odd。 它们都是用let作为前导关键字。

模板输入变量和模板引用变量是不同的,无论是在语义上还是语法上。

我们使用let关键字(如let hero)在模板中声明一个模板输入变量。 这个变量的范围被限制在所重复模板的单一实例上。
而声明模板引用变量使用的是给变量名加#前缀的方式(#var)。 一个引用变量引用的是它所附着到的元素、组件或指令。它可以在整个模板任意位置**访问。

模板输入变量和引用变量具有各自独立的命名空间。let hero中的hero和#hero中的hero并不是同一个变量。

总结:

<ng-template>在ng中主要通过viewChild TemplateRef ViewContainerRef来实现结构性操作。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
div失去焦点事件实现思路
Apr 22 Javascript
一款基jquery超炫的动画导航菜单可响应单击事件
Nov 02 Javascript
Javascript数组循环遍历之forEach详解
Nov 07 Javascript
函数四种调用模式以及其中的this指向
Jan 16 Javascript
vue 1.x 交互实现仿百度下拉列表示例
Oct 21 Javascript
js定时器实现倒计时效果
Nov 05 Javascript
详解Vue路由钩子及应用场景(小结)
Nov 07 Javascript
Angular4学习笔记router的简单使用
Mar 30 Javascript
如何在js代码中消灭for循环实例详解
Jul 29 Javascript
JQuery判断radio单选框是否选中并获取值的方法
Jan 17 jQuery
JavaScript实现酷炫的鼠标拖尾特效
Feb 18 Javascript
vue中控制mock在开发环境使用,在生产环境禁用方式
Apr 06 Vue.js
深入理解Vue 单向数据流的原理
Nov 09 #Javascript
node.js基于express使用websocket的方法
Nov 09 #Javascript
angular2系列之路由转场动画的示例代码
Nov 09 #Javascript
使用ef6创建oracle数据库的实体模型遇到的问题及解决方案
Nov 09 #Javascript
基于vue配置axios的方法步骤
Nov 09 #Javascript
微信小程序倒计时功能实现代码
Nov 09 #Javascript
js与jQuery实现的用户注册协议倒计时功能实例【三种方法】
Nov 09 #jQuery
You might like
codeigniter中实现一次性加载多个view的方法
2015/03/20 PHP
[原创]php简单隔行变色功能实现代码
2016/07/09 PHP
PHP正则表达式匹配替换与分割功能实例浅析
2017/02/04 PHP
php redis实现对200w用户的即时推送
2017/03/04 PHP
php扩展开发入门demo示例
2019/09/23 PHP
Nigma vs AM BO3 第二场2.13
2021/03/10 DOTA
JQUERY操作JSON实例代码
2010/02/09 Javascript
JavaScript 嵌套函数指向this对象错误的解决方法
2010/03/15 Javascript
ExtJS Store的数据访问与更新问题
2010/04/28 Javascript
jsvascript图像处理—(计算机视觉应用)图像金字塔
2013/01/15 Javascript
js创建对象的区别示例介绍
2014/07/24 Javascript
DeviceOne 让你一见钟情的App快速开发平台
2016/02/17 Javascript
浅谈Vue.js中ref ($refs)用法举例总结
2017/12/19 Javascript
微信小程序wx:for循环的实例详解
2018/10/07 Javascript
javascript实现鼠标点击生成文字特效
2019/12/24 Javascript
jQuery模仿ToDoList实现简单的待办事项列表
2019/12/30 jQuery
深入解读VUE中的异步渲染的实现
2020/06/19 Javascript
[47:52]DOTA2-DPC中国联赛正赛 iG vs LBZS BO3 第二场 3月4日
2021/03/11 DOTA
Python实现查找匹配项作处理后再替换回去的方法
2017/06/10 Python
详谈python http长连接客户端
2017/06/12 Python
Django Admin 实现外键过滤的方法
2017/09/29 Python
ubuntu16.04制作vim和python3的开发环境
2018/09/23 Python
Python运行不显示DOS窗口的解决方法
2018/10/22 Python
Python3中的bytes和str类型详解
2019/05/02 Python
Django框架设置cookies与获取cookies操作详解
2019/05/27 Python
python3实现猜数字游戏
2020/12/07 Python
用css3实现当鼠标移进去时当前亮其他变灰效果
2014/04/08 HTML / CSS
css3 盒模型以及box-sizing属性全面了解
2016/09/20 HTML / CSS
英国高街品牌:Miss Selfridge(塞尔弗里奇小姐)
2016/09/21 全球购物
丝芙兰中国官方商城:SEPHORA中国
2018/01/10 全球购物
微软美国官方网站:Microsoft美国
2018/05/10 全球购物
七一表彰活动方案
2014/01/18 职场文书
个人简历自我评价范文
2014/02/04 职场文书
2014年大学生党员评议表自我评价
2014/09/20 职场文书
解除劳动合同证明书模板
2014/11/20 职场文书
个人专业技术总结
2015/03/05 职场文书