4

给定一个项目列表(将其视为与多条消息的聊天),我想使用来显示每个项目的相对时间(例如自创建以来)。

每个项目都有自己的组件,并且使用以下代码显示相对时间:

get timeFromNow(): string {
  return moment(this.pageLoaded).fromNow(); // pageLoaded is a JS Date
}

问题是组件不会更新相对时间的显示,因为原始输入(pageLoaded在上面的示例中)不会改变。

我的问题是:是否有处理这种情况的最佳实践?目前,我正在使用markForCheckofChangeDetectorRef来触发重新渲染。但是,我不确定这在性能方面是否是一种好的方法。

在 Stackblitz 创建了一个简单的演示。在演示中,我使用上述markForCheck方法来触发更新。

4

2 回答 2

8

从技术角度来看,您有一个很好的解决方案。如果您想要更好的设计,请进入反应式编程的世界。

您可以使用流并让 Angular 完成工作,而不是手动启动检查:

export class MomentComponent implements OnInit  {
  pageLoaded: Moment;
  timeFromNow: Observable<string>;

  ngOnInit() {
    this.pageLoaded = moment(new Date());

    this.timeFromNow = interval(1000).pipe(
                         map(() => this.pageLoaded.fromNow()),
                         distinctUntilChanged()
                       );
  }
}

intervalsetInterval你的例子一样工作:它每 1000 毫秒发出一个值。然后我们用时间字符串替换这个值。而已。每秒都会发出一个新的时间字符串。我添加distinctUntilChanged()了一个新值,只有在它与旧值不同时才会发出它。

在您的模板中,您可以使用async管道使用流:

template: `Page loaded: <span class="relativeTime">{{ timeFromNow | async}}</span>`

当发出新的时间字符串时,HTML 将被更新。没有不必要的检查和计算。作为使用async管道的奖励,当组件被销毁并且您不会造成内存泄漏时,计时器会自动取消。

您可以查看分叉的演示

于 2018-07-01T12:02:59.927 回答
4

一个更好的解决方案是使用timer(0, 1000)而不是interval(1000). 这将立即触发,然后每秒触发一次。

http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-timer

于 2019-02-13T14:50:30.160 回答