angular编程教程:七爪源码Angular结构指令及其微语法
angular编程教程:七爪源码Angular结构指令及其微语法现在,在 <ng-template> 中放置一个指令,你就有了一个结构指令:但是当你将它包装在 <ng-template><div><p>Text</p></div></ng-template> 中时,你是在告诉 Angular “_declare div 标签的结构,使用 一个段落标签,带有字符串“Text”_”。 但请注意,现在我们并没有告诉 Angular 渲染它。模板是结构让我们开始定义它是什么。结构指令是具有结构的指令。 该结构是一个 ng 模板。 当你编写 <div><p>Text</p></div> 时,你是在告诉 Angular “_declare div 标签的结构,带有一个段落标签,带有字符串“Text”,并渲染它_” .
Angular 结构指令及其微语法
你有没有想过 *ngIf 和 *ngFor 的星号前缀是什么? 这称为结构性指令。
在本文中,我将向您展示您何时需要它以及它是如何工作的。
我还将做第 2 部分,向您展示如何创建自己的结构指令。
模板是结构
让我们开始定义它是什么。
结构指令是具有结构的指令。 该结构是一个 ng 模板。 当你编写 <div><p>Text</p></div> 时,你是在告诉 Angular “_declare div 标签的结构,带有一个段落标签,带有字符串“Text”,并渲染它_” .
但是当你将它包装在 <ng-template><div><p>Text</p></div></ng-template> 中时,你是在告诉 Angular “_declare div 标签的结构,使用 一个段落标签,带有字符串“Text”_”。 但请注意,现在我们并没有告诉 Angular 渲染它。
现在,在 <ng-template> 中放置一个指令,你就有了一个结构指令:
<ng-template [ngIf]="condition"><div><p>Text</p></div></ng-template>
合成糖
这就是 ngIf 的工作原理。 Angular 解析 <ng-template>,生成一个 TemplateRef,它被注入到 NgIf 指令中。如果传递给 ngIf 的条件为真,则呈现模板。
但是每次我们想使用 NgIf 或任何其他需要 ng-template 的指令时创建一个 ng-template 会很烦人。所以 Angular 团队创造了合成糖。就像一条捷径。
当您在指令前加上星号时,Angular 会将其包装在 ng-template 中并将指令应用于 ng-template。所以<div *ngIf=“condition”>Abc</div>,变成<ng-template [ngIf]=“condition”><div>Abc</div></ng-template>
这只是合成糖。如果您愿意,您可以编写不带星号前缀的整个应用程序。
只允许一个
了解了它的工作原理,您现在可以理解为什么我们只能对每个元素使用一个结构指令。如果你在同一个元素中使用 *ngIf 和 *ngFor,Angular 会如何去糖呢?先 ngIf 再 ngFor?相反?两者都在同一个模板中?
微语法
说到ngFor,好像比ngIf要复杂的多吧?我见过一些非常复杂的 ngFor 表达式,比如传递一个 trackBy 函数,管道一个 observable 数组,获取索引,并检查它是否是最后一个元素。
<div *ngFor="let item of list$ | async; trackBy: trackByFn; let itemIndex = index; let islast = last">{{ item }}</div>
最初,我认为这是 ngFor 特有的术语,但事实并非如此。 这是一个完整记录的语法,适用于任何结构指令,甚至是您最终创建的指令。 它被称为“结构指令微语法”。 (有点明显)
结构指令微语法将表达式用分号 (;) 分开。 在我们的 NgFor 示例中,我们有 4 个表达式:
- 让列表项$ | 异步
- trackBy:trackByFn
- 让 itemIndex = 索引
- 让 islast = 最后
声明
以 let 开头的表达式是变量声明。 您在 let 之后立即声明变量名称,并使用等号 (=) 将其指向导出指令上下文中的变量名称。
那是很多,对不起。
我的意思是当我们渲染一个 <ng-template> 时,我们可以选择传递一个上下文对象。 并且这个上下文对象的属性被传递给模板。 上下文对象可以有多个显式变量和一个隐式变量。
<!-- Rendering an <ng-template> with a context object -->
<ng-container *ngTemplateOutlet="templateExample; context: { $implicit: 'test' index: 1 }"></ng-container>
<!-- Using the context properties in the <ng-template> -->
<ng-template #templateExample let-itemIndex="index" let-item>
<p>#{{ itemIndex }} - {{ item }}</p>
</ng-template>
它就像一个 JavaScript 函数,我们有参数,我们声明了它,因此非常显式,我们有 this,它是一个隐式变量,即使我们没有声明它也存在。
function example(itemIndex isLast) {
// Explicit
console.log(itemIndex isLast);
// Implicit
console.log(this);
}
在一个函数中,你可以有任意多的参数,但只有一个 this。 就像这样,在 ng-template 中,您可以拥有任意数量的显式变量,但只有一个隐式变量。
当你不指向任何导出的变量时,你会得到隐式变量。 例如,let item 正在获取隐式变量。 但是让 isLast = last 得到显式的最后一个变量,让 itemIndex = index 得到显式的索引变量。
对变量进行脱糖处理后,我们得到:
<ng-template let-item let-itemIndex="index" let-isLast="last">
<p>#{{ itemIndex }} - {{ item }}</p>
<p *ngIf="isLast">The end</p>
</ng-template>
关键表达式
带有两个参数和它们之间的可选冒号 (:) 的表达式是键表达式。 表达式(右侧)被分配给前面带有前缀的键(左侧)。
让我们看一些例子。
在 \*ngIf="condition; else otherTemplate 中,对于 else otherTemplate 表达式:
- ngIf 是前缀
- 否则是关键
- otherTemplate 是表达式
这被脱糖为 <ng-template [ngIfElse]="otherTemplate"></ng-template>
在 *ngFor="let item of list; trackBy: trackByFn,对于 trackBy: trackByFn 表达式:
- ngFor 是前缀
- trackBy 是关键
- trackByFn 是表达式
这被脱糖为 <ng-template [ngForTrackBy]="trackByFn"></ng-template>
此外,对于那个 NgFor example,list 的 let item 中的 list 也是一个关键表达式。
- ngFor 是前缀
- of 是关键
- 列表是表达式
这被脱糖为 <ng-template [ngForOf]="list"></ng-template>
本地绑定
最后要提到的是表达式末尾的可选 as 关键字。 它声明一个模板变量并将表达式的结果映射到它。
*ngIf="condition as value" 变为 <ng-template [ngIf]="condition" let-value="ngIf">
结论
而已。 您现在了解了结构指令的工作原理以及如何分析它们的微语法。
我将写另一篇文章,介绍如何从头开始编写自定义结构指令以及如何告诉 Angular 编译器对其上下文进行类型检查。
祝你有美好的一天,很快见到你!