使用 Moment.js 自动更新相对时间的显示
Automatically update display of relative time with Moment.js
给定项目列表(将其视为包含多条消息的聊天),我想使用 moment.js 显示每个项目的相对时间(例如自创建以来)。
每个项目都有自己的组件,使用以下代码显示相对时间:
get timeFromNow(): string {
return moment(this.pageLoaded).fromNow(); // pageLoaded is a JS Date
}
问题是组件不会更新相对时间的显示,因为原始输入(上例中的pageLoaded
)不会改变。
我的问题是:是否有处理这种情况的最佳实践?目前,我正在使用 markForCheck
of ChangeDetectorRef
来触发重新渲染。但是,我不确定这是否是性能方面的好方法。
我创建了一个简单的 demo on Stackblitz。在演示中,我使用前面提到的 markForCheck
来触发更新。
从技术角度来看你有一个很好的解决方案。如果你想要更好的设计,那就进入响应式编程的世界吧。
您可以使用流并让 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()
);
}
}
interval
在您的示例中的工作方式类似于 setInterval
:它每 1000 毫秒发出一个值。然后我们用时间字符串替换这个值。而已。每秒都会发出一个新的时间字符串。我添加了 distinctUntilChanged()
以便只有当新值与旧值不同时才会发出新值。
在您的模板中,您可以使用 async
管道使用流:
template: `Page loaded: <span class="relativeTime">{{ timeFromNow | async}}</span>`
HTML 将在发出新的时间字符串时更新。没有不必要的检查和计算。作为使用 async
管道的奖励,当组件被销毁并且您不会造成内存泄漏时,计时器会自动取消。
您可以查看forked demo。
一个更好的解决方案是使用 timer(0, 1000)
而不是 interval(1000)
。这将立即触发,然后每秒触发一次。
见http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-timer
给定项目列表(将其视为包含多条消息的聊天),我想使用 moment.js 显示每个项目的相对时间(例如自创建以来)。
每个项目都有自己的组件,使用以下代码显示相对时间:
get timeFromNow(): string {
return moment(this.pageLoaded).fromNow(); // pageLoaded is a JS Date
}
问题是组件不会更新相对时间的显示,因为原始输入(上例中的pageLoaded
)不会改变。
我的问题是:是否有处理这种情况的最佳实践?目前,我正在使用 markForCheck
of ChangeDetectorRef
来触发重新渲染。但是,我不确定这是否是性能方面的好方法。
我创建了一个简单的 demo on Stackblitz。在演示中,我使用前面提到的 markForCheck
来触发更新。
从技术角度来看你有一个很好的解决方案。如果你想要更好的设计,那就进入响应式编程的世界吧。
您可以使用流并让 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()
);
}
}
interval
在您的示例中的工作方式类似于 setInterval
:它每 1000 毫秒发出一个值。然后我们用时间字符串替换这个值。而已。每秒都会发出一个新的时间字符串。我添加了 distinctUntilChanged()
以便只有当新值与旧值不同时才会发出新值。
在您的模板中,您可以使用 async
管道使用流:
template: `Page loaded: <span class="relativeTime">{{ timeFromNow | async}}</span>`
HTML 将在发出新的时间字符串时更新。没有不必要的检查和计算。作为使用 async
管道的奖励,当组件被销毁并且您不会造成内存泄漏时,计时器会自动取消。
您可以查看forked demo。
一个更好的解决方案是使用 timer(0, 1000)
而不是 interval(1000)
。这将立即触发,然后每秒触发一次。
见http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-timer