我正在学习Angular变化检测过程并检查Chrome中的开发工具,我看到了奇怪的行为.
我的plnkr演示了这种行为:http://plnkr.co/edit/cTLF00nQdhVmkHYc8IOu
我有一个简单的组件与视图:
@H_502_6@<li *ngFor="let item of list">{{item.name}}</li>和构造函数:
@H_502_6@constructor() { this.list = [{name: 'Gustavo'},{name: 'Costa'}]模拟我添加的简单请求:
@H_502_6@// simulating request repaint the DOM setInterval( () => { this.list = [{name: 'Gustavo'},{name: 'Costa'}]; },2000);如果您注意到,数组列表会收到一个等于初始值的列表.让我们假设当Angular在变更检测过程中检查视图中的值时,我们有这样的代码:
@H_502_6@if( oldName !== name ) { // ( 'Gustavo' !== 'Gustavo') // update the view }但是值是相同的,为什么角度每2秒重复一次DOM.?
但是如果我改变对象,则不会发生REPAINT
@H_502_6@// simulating request there is not repaint setInterval( () => { this.list[0].name = "Gustavo"; // no repaint because it's the same value this.list[1].name = "Costa 2"; // repaint },2000);您可以使用上面的plnkr链接进行测试.
解决方法
这是因为Angular使用默认的trackByFunction来跟踪按标识跟踪项目的DefaultIterableDiffer.
@H_502_6@const trackByIdentity = (index: number,item: any) => item;
很明显,当您创建一个新数组时,它会创建新的对象引用,而Angular会检测更改.即使您没有更改数组引用,Angular仍会认为项目已更改,因为对象引用更改:
@H_502_6@setInterval( () => { this.list.length = 0; this.list.push({name: 'Gustavo'}); this.list.push({name: 'Costa'}); },2000);您可以为您提供自定义trackByFunction以按对象名称进行跟踪:
@H_502_6@@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; }这样DOM就不会更新.见this plunker.
既然你是关于ng的好奇心,你也可以阅读this answer,其中我解释了ngFor如何工作.