阅读有关 Angular 中有 ngFor
语法的笔记内容。
它用来遍历某个集合(比如: 某一个阵列)中的每一个元素,并在遍历的当下为该元素渲染出属於它的样板到画面上。
[View]
<ul>
<li *ngFor="let user of userInfo; index as i">{{ i }} - {{ user.name }}</li>
</ul>
[TypeScript]
export class AppComponent {
userInfo = [{ name: 'Jared' }, { name: 'Tom' }, { name: 'Max' }];
}
上面的范例可以看到我们在 li 元素上加上了 ngFor 的内容,用以遍历 userInfo 的阵列内容,此时,当该阵列中的元素被遍历到的时候,就会为该元素产出一个 li 元素,所以, userInfo 是一个有三个元素的阵列,故画面上会被产出三个 li 元素。
以上范例的写法其实是 ngFor 语法的简写,那在官方文件有说明以上范例中的 ngFor 实际上 Angular 会把它翻译成这样
<ng-template ngFor let-user [ngForOf]="userInfo" let-i="index">
<li> {{ user.name }}</li>
</ng-template>
当 Angular 遇到 ngFor 前面的星号 *
(asterisk) ,它就会将产出一个 ng-template 将 ngFor 所在的元素包起来(以这边的范例是 li),接着,其他的属性对应的对象,我列在下面
ngFor: 对应到原本的 ngFor
[ngForof]="userInfo": 这句话的意思是要被遍历的对象为 userInfo
let-user: 对应到原本的 *ngFor="let user of userInfo"
中的 user
let-i="index": 对应到原本的 let index as i
在官方文件上还有特别列出了 ngFor 会产出的区域变数,
<li *ngFor="let user of users; index as i; first as isFirst">
{{i}}/{{users.length}}. {{user}} <span *ngIf="isFirst">default</span>
</li>
index: number: 当下被遍历到的元素在该所属阵列中的位置
count: number: 被遍历对象的元素总数,以上面的范例为例的话,就是 users.length
first: boolean: 当被遍历的当下元素是该被遍历对象的第一个元素时,会回传 true
last: boolean: 当被遍历的当下元素是该被遍历对象的最後一个元素时,会回传 true
even: boolean: 当被遍历的当下元素是该被遍历对象的偶数元素时,会回传 true
odd: boolean: 当被遍历的当下元素是该被遍历对象的奇数元素时,会回传 true
当改变 ngFor 所遍历目标的内容的时候, Angular 会以以下机制来处理 DOM 的内容
在许多产品中,很常会有当使用者送出某个更新後的内容後,再从 server 取回更新後的内容,接着再将它渲染到画面上。
这边做个简单的范例
[View]
<ul>
<li *ngFor="let user of userInfo; index as i">{{ i }} - {{ user.name }}</li>
</ul>
<button (click)="getUserInfoArray()">getUserInfo</button>
[TypeScript]
export class AppComponent {
userInfo = [{ name: 'Jared' }, { name: 'Tom' }, { name: 'Max' }];
getUserInfoArray() {
this.userInfo = [
{ name: 'Jared' },
{ name: 'Tom' },
{ name: 'Max' },
{ name: 'Wendy' },
{ name: 'Mars' },
{ name: 'Suns' },
];
}
}
以上范例的操作结果
可以看到以上的影片,当按下按钮,会模仿重新 GET 後的阵列内容并将其渲染到画面上。接着,在 DOM 上可以看到 ul 和 li 的 DOM 元素全部都有闪一次,有闪的部分就代表它被重新渲染到画面上了,由此可知, ul 和 li 全部都被重新渲染了。
但事实上并不是全部的阵列的内容都是新的,只有几个元素是新增的,这样的话,连那些重复的元素都被重新渲染的话,岂不很浪费浏览器的资源吗~~
所以,我们可以引用 ngFor 的 trackBy 属性来优化以上的情境,来改写一下上面的范例
[View]
<ul>
<li *ngFor="let user of userInfo; index as i; trackBy: trackByItems">{{ i }} - {{ user.name }}</li>
</ul>
<button (click)="getUserInfoArray()">getUserInfo</button>
[TypeScript]
export class AppComponent {
userInfo = [{ name: 'Jared' }, { name: 'Tom' }, { name: 'Max' }];
trackByItems(index, item) {
return item.name;
}
getUserInfoArray() {
this.userInfo = [
{ name: 'Jared' },
{ name: 'Tom' },
{ name: 'Max' },
{ name: 'Wendy' },
{ name: 'Mars' },
{ name: 'Suns' },
];
}
}
可以看到我们在 ngFor 的内容中,加入 trackBy: trackByItems
代表它会去追踪 trackByItems 这个函式回传的内容。在 trackByItems 函式有两个参数分别是 index 和 item ,index 就代表该元素在其所属阵列中的元素位置, item 的话就代表遍历当下的元素。然後,我们会回传 item.name 就是代表去鉴察是否该元素的 name 属性内容是之前阵列没有的。
以上这个新增的程序码效果,为若该元素的 name 属性内容没有变化的话,该元素的 template 是不会被重新渲染的喔。
让我们来看一下修改後的操作结果
可以发现并不是所有 ul 里面的 li 都被重新渲染,只有那些跟原本阵列元素内容不同的部分会被重新渲染,是不是很赞呢~~
来做个总结吧
本文同步更新於blog 情境:这是公司生产的文字积木 <?php namespace Ap...
集合的特性 可以依照集合是否具有「自动排序性」、「重复性」、「次序性」及「使用关键值」,为资料选择适...
接续介绍 ML 专案生命周期,本日说明第 2 阶段「资料 Data」的工作流程,依其说法分为2大步...
上一期说到Micro LED的厉害之处,不过今天要说的是Micro OLED,Micro OLED继...
点开Project Settings的other,把Scripting Backend改为IL2CP...