[英]How to use `trackBy` with `ngFor`
我真的不明白我應該從trackBy
返回什么。 根據我在網上看到的一些示例,我應該返回對象上某些屬性的值。 這樣對嗎? 為什么要獲取index
作為參數?
例如,在以下情況下:
組件.component.ts
constructor() {
window.setInterval(() => this.users = [
{ name: 'user1', score: Math.random() },
{ name: 'user2', score: Math.random() }
],
1000);
}
userByName(index, user) {
return user.name;
}
組件.template.html
<div *ngFor="let user of users; trackBy:userByName">
{{user.name}} -> {{user.score}}
</div>
盡管名稱未更改,但此模板中顯示的對象仍會更新。 為什么?
在為ngForOf
指令觸發的每個ngDoCheck
上,Angular 都會檢查哪些對象發生了變化。 它在這個過程中使用了差異,每個差異都使用trackBy
函數將當前對象與新對象進行比較。 默認trackBy
函數按身份跟蹤項目:
const trackByIdentity = (index: number, item: any) => item;
它接收當前項目並且應該返回一些值。 然后將函數返回的值與此函數上次返回的值進行比較。 如果值發生變化,diff 報告變化。 因此,如果默認函數返回對象引用,則如果對象引用發生更改,它將與當前項不匹配。 因此,您可以提供將返回其他內容的自定義trackBy
函數。 比如對象的一些鍵值。 如果此鍵值與前一個鍵值匹配,則 Angular 將不會檢測到更改。
語法...trackBy:userByName
不再受支持。 您現在必須提供函數引用。 這是基本示例:
setInterval( () => {
this.list.length = 0;
this.list.push({name: 'Gustavo'});
this.list.push({name: 'Costa'});
}, 2000);
@Component({
selector: 'my-app',
template: `
<li *ngFor="let item of list; trackBy:identify">{{item.name}}</li>
`
})
export class App {
list:[];
identify(index, item){
return item.name;
}
由於這個話題仍然很活躍,而且很難找到一個明確的答案,所以除了@Max的答案之外,我還要添加幾個例子:
app.component.ts
array = [
{ "id": 1, "name": "bill" },
{ "id": 2, "name": "bob" },
{ "id": 3, "name": "billy" }
]
foo() {
this.array = [
{ "id": 1, "name": "foo" },
{ "id": 2, "name": "bob" },
{ "id": 3, "name": "billy" }
]
}
identify(index, item) {
return item.id;
}
讓我們使用*ngFor
將array
顯示為 3 個 div。
app.component.html
沒有 trackBy的*ngFor
示例:
<div *ngFor="let e of array;">
{{e.id}} - {{e.name}}
</div>
<button (click)="foo()">foo</button>
如果我們點擊foo
按鈕會發生什么?
→ 3 個 div 將被刷新。 自己嘗試一下,打開你的控制台進行驗證。
帶有 trackBy的*ngFor
示例:
<div *ngFor="let e of array; trackBy: identify">
{{e.id}} - {{e.name}}
</div>
<button (click)="foo()">foo</button>
如果我們點擊foo
按鈕會發生什么?
→ 只有第一個 div 會被刷新。 自己嘗試一下,打開你的控制台進行驗證。
如果我們更新第一個對象而不是整個對象呢?
foo() {
this.array[0].name = "foo";
}
→ 這里不需要使用trackBy
。
它在使用通常看起來像我用array
模式化的Subscription時特別有用。 所以它看起來像:
array = [];
subscription: Subscription;
ngOnInit(): void {
this.subscription = this.fooService.getArray().subscribe(data => {
this.array = data;
});
}
identify(index, item) {
return item.id;
}
從文檔中:
為避免這種昂貴的操作,您可以自定義默認跟蹤算法。 通過向 NgForOf 提供 trackBy 選項。 trackBy 接受一個有兩個參數的函數:index 和 item。 如果給出了 trackBy,Angular 會根據函數的返回值跟蹤變化。
在此處閱讀更多信息: https ://angular.io/api/common/NgForOf
在這里找到我的原始答案: https ://stackoverflow.com/a/57890227/9753985
這是我在我的項目中使用的,以允許通過迭代模型的屬性進行跟蹤,而無需在組件的類中編寫函數:
import { Host, Directive, Input } from "@angular/core";
import { NgForOf } from "@angular/common";
@Directive({
selector: "[ngForTrackByProperty]"
})
export class TrackByPropertyDirective {
private _propertyName: string = "";
public constructor(@Host() private readonly _ngFor: NgForOf<any>) {
this._ngFor.ngForTrackBy = (_: number, item: any) => this._propertyName ? item[this._propertyName] : item;
}
@Input("ngForTrackByProperty")
public set propertyName(value: string | null) {
// We must accept null in case the user code omitted the ": 'somePropName'" part.
this._propertyName = value ?? "";
}
}
用法 :
<some-tag *ngFor="let item of models; trackByProperty: 'yourDiscriminantProp'">
app.component.html
<button class="btn btn-warning" (click)="loadCourses()">LoadCourses</button>
<ul>
<li *ngFor="let course of courses; trackBy:trackCourse">
{{course.name}}
</li>
</ul>
app.component.ts
loadCourses() {
this.courses = [
{id:1, name:'cour1'},
{id:2, name:'cour2'},
{id:3, name:'cour3'}
]
};
trackCourse(index : number, course: any) {
return course ? course.id : undefined;
};
Mosh的參考代碼您可以在指令部分找到
使用 trackBy 的目的是在可迭代對象中設置元素的標識。 如果 Angular 看到兩個具有相同標識的元素,它將繼續檢查元素的內容,並且只有在內容發生更改時才會重新繪制。 如果沒有標識,Angular 將依賴元素的對象引用,即使內容相同,通常也會發生變化,因此 Angular 會因為引用不同而重新繪制元素。
這個有角度NgFor
文檔將為您提供幫助。 https://angular.io/docs/ts/latest/api/common/index/NgFor-directive.html
<div *ngFor="let user of users; trackBy:user?.name">
{{user.name}} -> {{user.score}}
</div>
否則你可以使用
*ngFor="a of array; index as i;"
和
[attr.data-target]="'#test' + i"
和
name="test{{i}}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.