angular之ng

网友投稿 284 2023-03-19


angular之ng

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

html5中的template

template标签的含义:HTML

属性

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

示例

html

UPC_Code

Product_Name

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);

http://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

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

以ngIf为例:

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

通过阅读ngIf源码学习如何运用

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

会被解析为

`

看下ngIf源码

import {Directive, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef} from '@angular/core';

@Directive({selector: '[ngIf]'})

export class NgIf {

private _context: NgIfContext = new NgIfContext();

private _thenTemplateRef: TemplateRef|null = null;

private _elseTemplateRef: TemplateRef|null = null;

private _thenViewRef: EmbeddedViewRef|null = null;

private _elseViewRef: EmbeddedViewRef|null = null;

constructor(private _viewContainer: ViewContainerRef, templateRef: TemplateRef) {

this._thenTemplateRef = templateRef;

}

@Input()

set ngIf(condition: any) {

this._context.$implicit = this._context.ngIf = condition;

this._updateView();

}

@Input()

set ngIfThen(templateRef: TemplateRef) {

this._thenTemplateRef = templateRef;

this._thenViewRef = null; // clear previous view if any.

this._updateView();

}

@Input()

set ngIfElse(templateRef: TemplateRef) {

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取得的内容,并通过ViewContainerRef来访问这个视图容器。

TemplateRef

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

abstract get elementRef(): ElementRef;

abstract createEmbeddedView(context: C): EmbeddedViewRef;

}

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

template test

@ViewChild('tptest') tptest: TemplateRef;

ViewContainerRef

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

export abstract class ViewContainerRef {

/*基于TemplateRef对象创建Embedded View(内嵌视图),然后根据`index`指定的值,插入到容器中。

如果没有指定`index`的值,新创建的视图将作为容器中的最后一个视图插入。*/

abstract createEmbeddedView(

templateRef: TemplateRef, //内嵌视图

context?: C, index?: number): // 创建上下文

EmbeddedViewRef;

}

createEmbeddedView:context

创建Template 自身 Context 的属性,以ngFor为例:

查看ngFor Context源码:

export class NgForOfContext {

constructor(

public $implicit: T, public ngForOf: NgIterable, 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; }

}

({{i}}) {{hero.name}}

解析后:

从例子中可以看到,通过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中主要通过viewChild TemplateRef ViewContainerRef来实现结构性操作。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java实现生产者消费者问题与读者写者问题详解
下一篇:路由器管理密码怎么破(路由器管理密码忘了怎么弄)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~