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 相关文章推荐
ext for eclipse插件安装方法
Apr 27 Javascript
javascript 读取xml,写入xml 实现代码
Jul 10 Javascript
js 覆盖和重载 函数
Sep 25 Javascript
获取body标签的两种方法
Oct 13 Javascript
jquery多行滚动/向左或向上滚动/响应鼠标实现思路及代码
Jan 23 Javascript
jquery数据验证插件(自制,简单,练手)实例代码
Oct 24 Javascript
jquery幻灯片插件bxslider样式改进实例
Oct 15 Javascript
javascript实现获取浏览器版本、操作系统类型
Jan 29 Javascript
JavaScript数组和循环详解
Apr 27 Javascript
JavaScript Array对象详解
Mar 01 Javascript
js数组操作方法总结(必看篇)
Nov 22 Javascript
ES5 ES6中Array对象去除重复项的方法总结
Apr 27 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
详解:――如何将图片储存在数据库里
2006/12/05 PHP
php操作MongoDB基础教程(连接、新增、修改、删除、查询)
2014/03/25 PHP
使用pthreads实现真正的PHP多线程(需PHP5.3以上版本)
2014/05/05 PHP
destoon整合ucenter后注册页面不跳转的解决方法
2014/06/21 PHP
PHP中IP地址与整型数字互相转换详解
2014/08/20 PHP
PHP中strpos、strstr和stripos、stristr函数分析
2016/06/11 PHP
ThinkPHP的SAE开发相关注意事项详解
2016/10/09 PHP
newxtree.js代码
2007/03/13 Javascript
JavaScript 无符号右移运算符
2009/04/17 Javascript
jQuery对象数据缓存Cache原理及jQuery.data方法区别介绍
2013/04/07 Javascript
js中parseInt函数浅谈
2013/07/31 Javascript
jquery插件NProgress.js制作网页加载进度条
2015/06/05 Javascript
JS+Canvas 实现下雨下雪效果
2016/05/18 Javascript
jQuery基本过滤选择器用法示例
2016/09/09 Javascript
详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件
2017/06/01 jQuery
老生常谈js数据类型
2017/08/03 Javascript
jQuery实现切换隐藏与显示同时切换图标功能
2017/10/29 jQuery
基于vue-resource jsonp跨域问题的解决方法
2018/02/03 Javascript
vue项目引入字体.ttf的方法
2018/09/28 Javascript
js实现点击展开隐藏效果(实例代码)
2018/09/28 Javascript
vue-cli3.0 脚手架搭建项目的过程详解
2018/10/19 Javascript
JavaScript中的null和undefined用法解析
2019/09/30 Javascript
vue分页插件的使用方法
2019/12/25 Javascript
python采用django框架实现支付宝即时到帐接口
2016/05/17 Python
Python基于Matplotlib库简单绘制折线图的方法示例
2017/08/14 Python
python获取全国城市pm2.5、臭氧等空气质量过程解析
2019/10/12 Python
详解如何在pyqt中通过OpenCV实现对窗口的透视变换
2020/09/20 Python
python实现sm2和sm4国密(国家商用密码)算法的示例
2020/09/26 Python
HTML5 input placeholder 颜色修改示例
2014/05/30 HTML / CSS
世界上最大的网络主机公司:1&1
2016/10/12 全球购物
戴尔英国官网:Dell英国
2017/05/27 全球购物
应届生财务会计求职信
2013/11/05 职场文书
读书心得体会
2013/12/28 职场文书
学生偷窃检讨书
2014/09/25 职场文书
政风行风自查自纠报告
2014/10/21 职场文书
nginx常用命令放入shell脚本详解
2021/03/31 Servers