Angular 防止重新创建元素
Angular prevent recreation of elements
所以我有一个组件可以加载 divs 动画。
div 是基于数据源显示的。
*注意:例子中我用了很多<any>
,那是因为我还没有决定模型
apiService.ts
dataArray: Observable<Array<any>>;
constructor(){
this.getUpdateData();
setInterval(()=> this.getUpdateData(), 1000);
}
getUpdateData(){
this.httpClientCall()
.subscribe((response: any) => {
this.dataArray = response;
});
}
component.html
<div class="panels" *ngFor="let data of apiService.dataArray">
<div class="panel-that-has-animation">
{{ data.some_value_that_can_be_updated }}
</div>
</div>
简单分解:我每分钟从远程拉取数据,并让响应为dataArray
内的新数据。
我遇到的问题是每次更新时,整个 panels
div 的内容都会被替换。
我只想更新值而不是重新渲染整个 div。
数组本身由对象组成,我真正喜欢做的是更新数组中的对象 属性,而不是替换整个对象数组。更确切;比较 2 个数组并检查对象的属性是否存在差异。
示例:
[
0: {id: 1, name: a, group: 'a'},
1: {id: 2, name: b, group: 'b'},
2: {id: 3, name: c, group: 'c'},
]
新数据(来自 httpClient):
[
0: {id: 1, name: a, group: 'b'},
1: {id: 2, name: b, group: 'b'},
2: {id: 3, name: c, group: 'c'},
]
在示例中,我想更新数组中的第一个对象,因为组字符串已更改,而不是替换整个对象数组。
我永远感激 why/how 的解决方案,而不仅仅是解决此问题的代码。
提前致谢!
*ngFor
可以利用 trackBy
函数将数组元素关联到 DOM 元素。这允许 angular 更有效地更新 DOM,因为它将不再销毁和重新创建所有项目,而只会创建新项目。
只需在您的控制器中创建一个小函数:
trackById = (index: number, item: Item) => item.id;
然后像这样将其添加到您的 *ngFor
中:
<div class="panels" *ngFor="let data of apiService.dataArray; trackBy: trackById">
<div class="panel-that-has-animation">
{{ data.some_value_that_can_be_updated }}
</div>
</div>
现在您应该会看到,随着源数据的更改,只会创建新项目(动画),现有项目将保留。
另外,这不是你问题的一部分,但我想提一下你可以简化你的服务代码:
constructor(){
this.getUpdateData();
setInterval(()=> this.getUpdateData(), 1000);
}
getUpdateData(){
this.httpClientCall()
.subscribe((response: any) => {
this.dataArray = response;
});
}
收件人:
dataArray$: Observable<Array<any>> = timer(0, 1000).pipe(
switchMapTo(this.httpClientCall())
);
这有一个额外的好处就是懒惰;即 - 如果 dataArray$
没有订阅者,您将不会轮询服务器。
所以我有一个组件可以加载 divs 动画。 div 是基于数据源显示的。
*注意:例子中我用了很多<any>
,那是因为我还没有决定模型
apiService.ts
dataArray: Observable<Array<any>>;
constructor(){
this.getUpdateData();
setInterval(()=> this.getUpdateData(), 1000);
}
getUpdateData(){
this.httpClientCall()
.subscribe((response: any) => {
this.dataArray = response;
});
}
component.html
<div class="panels" *ngFor="let data of apiService.dataArray">
<div class="panel-that-has-animation">
{{ data.some_value_that_can_be_updated }}
</div>
</div>
简单分解:我每分钟从远程拉取数据,并让响应为dataArray
内的新数据。
我遇到的问题是每次更新时,整个 panels
div 的内容都会被替换。
我只想更新值而不是重新渲染整个 div。
数组本身由对象组成,我真正喜欢做的是更新数组中的对象 属性,而不是替换整个对象数组。更确切;比较 2 个数组并检查对象的属性是否存在差异。
示例:
[
0: {id: 1, name: a, group: 'a'},
1: {id: 2, name: b, group: 'b'},
2: {id: 3, name: c, group: 'c'},
]
新数据(来自 httpClient):
[
0: {id: 1, name: a, group: 'b'},
1: {id: 2, name: b, group: 'b'},
2: {id: 3, name: c, group: 'c'},
]
在示例中,我想更新数组中的第一个对象,因为组字符串已更改,而不是替换整个对象数组。
我永远感激 why/how 的解决方案,而不仅仅是解决此问题的代码。 提前致谢!
*ngFor
可以利用 trackBy
函数将数组元素关联到 DOM 元素。这允许 angular 更有效地更新 DOM,因为它将不再销毁和重新创建所有项目,而只会创建新项目。
只需在您的控制器中创建一个小函数:
trackById = (index: number, item: Item) => item.id;
然后像这样将其添加到您的 *ngFor
中:
<div class="panels" *ngFor="let data of apiService.dataArray; trackBy: trackById">
<div class="panel-that-has-animation">
{{ data.some_value_that_can_be_updated }}
</div>
</div>
现在您应该会看到,随着源数据的更改,只会创建新项目(动画),现有项目将保留。
另外,这不是你问题的一部分,但我想提一下你可以简化你的服务代码:
constructor(){
this.getUpdateData();
setInterval(()=> this.getUpdateData(), 1000);
}
getUpdateData(){
this.httpClientCall()
.subscribe((response: any) => {
this.dataArray = response;
});
}
收件人:
dataArray$: Observable<Array<any>> = timer(0, 1000).pipe(
switchMapTo(this.httpClientCall())
);
这有一个额外的好处就是懒惰;即 - 如果 dataArray$
没有订阅者,您将不会轮询服务器。