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 相关文章推荐
JavaScript arguments 多参传值函数
Oct 24 Javascript
functional继承模式 摘自javascript:the good parts
Jun 20 Javascript
jquery动态添加删除(tr/td)
Feb 09 Javascript
javascript 对象数组根据对象object key的值排序
Mar 09 Javascript
谈谈AngularJs中的隐藏和显示
Dec 09 Javascript
javaScript生成支持中文带logo的二维码(jquery.qrcode.js)
Jan 03 Javascript
vue中各种通信传值方式总结
Feb 14 Javascript
Paypal支付不完全指北
Jun 04 Javascript
Vue Render函数创建DOM节点代码实例
Jul 08 Javascript
vue实现自定义多选按钮
Jul 16 Javascript
js实现贪吃蛇游戏 canvas绘制地图
Sep 09 Javascript
JavaScript用document.write()输出换行的示例代码
Nov 26 Javascript
深入理解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
PHP中call_user_func_array()函数的用法演示
2012/02/05 PHP
使用php实现截取指定长度
2013/08/06 PHP
php生成EAN_13标准条形码实例
2013/11/13 PHP
PHP+jquery+CSS制作头像登录窗(仿QQ登陆)
2016/10/20 PHP
在laravel框架中使用model层的方法
2019/10/08 PHP
img onload事件绑定各浏览器均可执行
2012/12/19 Javascript
javascript编码的几个方法详细介绍
2013/01/06 Javascript
php跨域调用json的例子
2013/11/13 Javascript
JavaScript事件委托实例分析
2015/05/26 Javascript
浅谈Javascript中的12种DOM节点类型
2016/08/19 Javascript
JS实现双击内容变为可编辑状态
2017/03/03 Javascript
vue swipe自定义组件实现轮播效果
2019/07/03 Javascript
Vue.js实现tab切换效果
2019/07/24 Javascript
js实现随机抽奖
2020/03/19 Javascript
vue过滤器实现日期格式化的案例分析
2020/07/02 Javascript
Vue+Element自定义纵向表格表头教程
2020/10/26 Javascript
vue点击Dashboard不同内容 跳转到同一表格的实例
2020/11/13 Javascript
[46:23]OG vs EG 2018国际邀请赛淘汰赛BO3 第一场 8.23
2018/08/24 DOTA
Python中为feedparser设置超时时间避免堵塞
2014/09/28 Python
TensorFlow搭建神经网络最佳实践
2018/03/09 Python
python+jinja2实现接口数据批量生成工具
2019/08/28 Python
Python爬虫设置Cookie解决网站拦截并爬取蚂蚁短租的问题
2021/02/22 Python
加利福尼亚州威尼斯的女性奢侈品设计师服装和概念店:Mona Moore
2018/09/13 全球购物
生物技术毕业生自荐信
2013/10/23 职场文书
应届生英语教师求职信
2013/11/05 职场文书
财务管理专业推荐信
2013/11/19 职场文书
中学生自我评价范文
2014/02/08 职场文书
小学毕业感言300字
2014/02/19 职场文书
合作协议书范本
2014/04/17 职场文书
幼儿教师师德师风演讲稿
2014/08/22 职场文书
2014年销售工作总结与计划
2014/12/01 职场文书
2015年领班工作总结
2015/04/29 职场文书
2016教师党员学习心得体会
2016/01/21 职场文书
解除合同协议书范本
2016/03/21 职场文书
DSP接收机前端设想
2022/04/05 无线电
Nginx+Tomcat负载均衡多实例详解
2022/04/11 Servers