Max*_*kyi 32 angularjs-track-by ngfor angular
我真的不明白我应该从什么地方回来trackBy.根据我在网上看到的例子,我应该返回对象上某些属性的值.这是对的吗?为什么我将索引作为参数?
例如,在以下情况中:
constructor() {
window.setInterval(() => this.users = [
{name: 'user1', score: Math.random()},
{name: 'user2', score: Math.random()}],
1000);
}
userByName(index, user) {
return user.name;
}
...
<div *ngFor="let user of users; trackBy:userByName">{{user.name}} -> {{user.score}}</div>
Run Code Online (Sandbox Code Playgroud)
尽管名称未更改,但模板中显示的对象仍会更新.为什么?
Max*_*kyi 39
在每次ngDoCheck触发ngForOf指令时,Angular会检查哪些对象已更改.它对此过程使用不同,每个都使用不同的trackBy函数来比较当前对象和新对象.默认trackBy功能按标识跟踪项目:
const trackByIdentity = (index: number, item: any) => item;
Run Code Online (Sandbox Code Playgroud)
它接收当前项并应返回一些值.然后将函数返回的值与此函数上次返回的值进行比较.如果值更改,则差异会报告更改.因此,如果默认函数返回对象引用,则在对象引用已更改时,它将与当前项不匹配.因此,您可以提供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;
}
Run Code Online (Sandbox Code Playgroud)
虽然对象引用更改,但DOM不会更新.这是掠夺者.如果你很好奇如何ngFor在幕后工作,请阅读这个答案.
Cur*_*rse 32
由于这个话题仍然很活跃并且很难找到明确的答案,所以除了@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;
}
Run Code Online (Sandbox Code Playgroud)
让我们array使用*ngFor.
应用程序组件.html
的实施例*ngFor ,而不trackBy:
<div *ngFor="let e of array;">
{{e.id}} - {{e.name}}
</div>
<button (click)="foo()">foo</button>
Run Code Online (Sandbox Code Playgroud)
如果我们点击foo按钮会发生什么?
? 3 个 div 将被刷新。自己尝试一下,打开控制台进行验证。
的实施例*ngFor 与trackBy:
<div *ngFor="let e of array; trackBy: identify">
{{e.id}} - {{e.name}}
</div>
<button (click)="foo()">foo</button>
Run Code Online (Sandbox Code Playgroud)
如果我们点击foo按钮会发生什么?
? 只有第一个 div 会被刷新。自己尝试一下,打开控制台进行验证。
如果我们更新第一个对象而不是整个对象呢?
foo() {
this.array[0].name = "foo";
}
Run Code Online (Sandbox Code Playgroud)
? 这里没有必要使用trackBy。
它在使用Subscription时特别有用,它通常看起来像我用array. 所以它看起来像:
array = [];
subscription: Subscription;
ngOnInit(): void {
this.subscription = this.fooService.getArray().subscribe(data => {
this.array = data;
});
}
identify(index, item) {
return item.id;
}
Run Code Online (Sandbox Code Playgroud)
从文档:
为了避免这种昂贵的操作,您可以自定义默认跟踪算法。通过向 NgForOf 提供 trackBy 选项。trackBy 接受一个有两个参数的函数:index 和 item。如果给定了 trackBy,Angular 会根据函数的返回值跟踪变化。
在此处阅读更多信息:https : //angular.io/api/common/NgForOf
在这里找到我的原始答案:https : //stackoverflow.com/a/57890227/9753985
Rém*_*ery 22
以下是我在项目中使用的内容,允许通过迭代模型的属性进行跟踪,而无需在组件的类中编写函数的麻烦:
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 ?? "";
}
}
Run Code Online (Sandbox Code Playgroud)
用法 :
<some-tag *ngFor="let item of models; trackByProperty: 'yourDiscriminantProp'">
Run Code Online (Sandbox Code Playgroud)
应用程序组件.html
<button class="btn btn-warning" (click)="loadCourses()">LoadCourses</button>
<ul>
<li *ngFor="let course of courses; trackBy:trackCourse">
{{course.name}}
</li>
</ul>
Run Code Online (Sandbox Code Playgroud)
应用程序组件.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;
};
Run Code Online (Sandbox Code Playgroud)
Mosh 的 参考代码您可以在指令部分找到
小智 5
使用 trackBy 的目的是设置可迭代中元素的标识。如果 Angular 看到两个具有相同标识的元素,它将继续检查元素的内容,并且只有在内容发生更改时才会重新绘制/重新渲染。如果没有标识,Angular 将依赖元素的对象引用,即使内容相同,这些元素通常也会发生变化,因此 Angular 会因为不同的引用而重新绘制/重新渲染元素。
| 归档时间: |
|
| 查看次数: |
31873 次 |
| 最近记录: |