我想渲染一个视觉倒数计时器.我正在使用这个组件,
https://github.com/crisbeto/angular-svg-round-progressbar,它依赖于SimpleChange来提供changes.current.previousValue& changes.current.currentValue.
这是模板代码
<ion-card class="timer"
*ngFor="let snapshot of timers | snapshot"
>
<ion-card-content>
<round-progress
[current]="snapshot.remaining"
[max]="snapshot.duration"
[rounded]="true"
[responsive]="true"
[duration]="800"
>
</round-progress>
</ion-card>
我正在使用此代码来触发angular2变化检测
this._tickIntervalHandler = setInterval( ()=>{
// run change detection
return;
}
// interval = 1000ms
, interval
)
更新
(经过大量测试,我发现问题不是我渲染时的精确度,而且这个问题已经改变以反映出来.)
问题是在1个变化检测循环内多次调用ngFor.无论我的tick时间间隔或snapshot.remaining(即秒或十分之一秒)的精度如果在更改检测期间后续调用ngFor时,snapshot.remaining发生变化,我都会收到异常:
检查后表情发生了变化
如果我只渲染一个计时器而不使用ngFor,那么更改检测工作正常 – 即使是10ms的间隔.
如何在页面上渲染多个计时器,大概使用ngFor,而不会触发此异常?
解
经过一些测试后,似乎问题是使用带有ngFor的SnapshotPipe来捕获Timer数据的快照.最终工作的是在View Component中获取Timer数据的快照.如下面的答案所述,这使用pull方法来获取更改,而不是push方法.
// timers.ts
export class TimerPage {
// use with ngFor
snapshots: Array<any> = [];
constructor(timerSvc: TimerSvc){
let self = this;
timerSvc.setIntervalCallback = function(){
self.snapshots = self.timers.map( (timer)=>timer.getSnapshot() );
}
}
}
// timer.html
<ion-card class="timer" *ngFor="let snapshot of snapshots">
<ion-card-content>
<round-progress
[current]="snapshot.remaining"
[max]="snapshot.duration"
[rounded]="true"
[responsive]="true"
[duration]="800"
>
</round-progress>
</ion-card>
// TimerSvc can start the tickInterval
export class TimerSvc {
_tickIntervalCallback: ()=>void;
_tickIntervalHandler: number;
setIntervalCallback( cb: ()=>void) {
this._tickIntervalCallback = cb;
}
startTicking(interval:number=100){
this._tickIntervalHandler = setInterval(
this._tickIntervalCallback
, interval
);
}
}
最佳答案 第一个可疑的东西是toJSON(它有错误的名字或返回字符串或将字符串转换为数组),哪些对象包含在timers数组中?
在更改期间,可能会多次评估循环,因此不应生成新对象.另外toJSON管道应该标记为pure(参见Pipe decorator选项).另外最好为ngFor提供trackBy函数.通常,在这种情况下更好的是更新类字段而不是使用管道.
public snapshots:any[] = [];
private timers:any[] = [];
setInterval(()=>{
this.snapshots = this.updateSnapshots(this.timers);
}, 100);
<ion-card class="timer"
*ngFor="let snapshot of snapshots"
>