angular2 你如何在 `ngFor` 内渲染一个计时器组件

标签 angular ionic2 zonejs

我想渲染一个视觉倒数计时器。我正在使用这个组件,https://github.com/crisbeto/angular-svg-round-progressbar ,它依赖于 SimpleChange 来传递 changes.current.previousValuechanges.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
  )

已更新 (经过多次测试,我发现问题不在于我渲染的时间精度,并且已更改此问题以反射(reflect)这一点。)

问题是 ngFor 在 1 个变化检测循环中被多次调用。无论我的滴答间隔或 snapshot.remaining 的精度如何(即秒或十分之一秒)如果 snapshot.remaining 在随后调用 ngFor 时发生变化 在更改检测期间,我得到一个异常:

检查后表达式发生了变化

如果我在不使用 ngFor 的情况下只渲染一个计时器,那么变化检测就可以正常工作——即使是 10ms 的间隔也是如此。

我如何在一个页面上呈现多个计时器,大概使用 ngFor,而不触发此异常?

解决方案

经过一些测试,问题似乎出在使用带有 ngForSnapshotPipe 来捕获计时器数据的快照。最终起作用的是获取 View 组件中计时器数据的快照。正如下面的答案中提到的,这使用 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(它有错误的名称或返回string或将字符串转换为数组),哪些对象包含在timers 数组?

在变更检测期间,for 循环可能会被评估多次,因此它不应生成新对象。此外,toJSON 管道应标记为 pure(请参阅管道装饰器选项)。另外最好为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"
> 

关于angular2 你如何在 `ngFor` 内渲染一个计时器组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42137532/

相关文章:

angularjs - Safari 中的混合 AngularJS 和 Angular 应用程序性能低下

javascript - 使用 Zone.js 获取无区域窗口方法

angular - 你如何在 Angular 中使用计算/计算的属性?

arrays - Angular 将带有字段的 API JSON 响应对象转换为数组

javascript - Redux:这算作变异状态吗?

javascript - 奇怪的 IONIC 错误消息

angular - 使用 ~(波形符)导入 SCSS 文件在 Angular 6 中不起作用

javascript - ionic 2中后台进程调用api

ionic2 - 屏幕底部的 ionic 粘滞按钮

javascript - 如何通过 chrome-remote-interface 远程评估 Angular 应用程序的 promise