1

我需要在我的 Angular 4/5 应用程序中构建一个 TimeZone 选择器。当用户更改时区时,我希望页面上所有显示的时间值都会立即更新。

我打算使用:

  • 使用时区支持的 momentjsangular2-momentangular-moment-timezone.
  • 要格式化日期,请使用amLocal管道,然后是其他管道。
  • 当用户选择不同的时区时,我打算打电话moment.tz.setDefault(_timezone)

从此时起,上述值被格式化为新时区,而当前显示的时间值不会改变。角度变化检测机制不会更新显示的时间值,因为输入值没有改变。

由于性能开销(考虑到时区更改不是频繁的活动),我不想创建一个“不纯”的管道。

作为后备,我可以创建一个将当前时区作为参数的管道(或使用现有的管道)。它确实有效,但我需要将当前时区值传递给每个组件和模板。

即使值没有变化,我也无法找到一种方法让 Angular 变化检测相信存在变化。

任何建议都将受到欢迎。

4

2 回答 2

2

管道不是组件(很明显),它们没有自己的变化检测机制,除了pure标志。所以有两种方法可以达到预期的效果:

  1. 使用智能不纯管道,它将跟踪以前的值和以前的格式化结果。Angular AsyncPipe(实际上是不纯的,如果有另一种方法可以做到这一点,那么我相信它会变得纯正)以这种方式实现:

    if (value !== this.value || this.timeZoneChanged) 
    {
        this.value = value;
        this.formattedValue = ... render value ...;
    }
    return this.formattedValue;
    

    AsyncPipe您可以在 github 上浏览源代码。

  2. 使用自定义组件来呈现日期,即 custom ControlValueAccessor
于 2017-11-14T01:26:07.043 回答
1

例如,在使用时ngx-translate,切换语言意味着获取新的翻译。正如您在此处看到的,他们使用不纯的管道,正如您所说,这意味着性能问题。

我想象的另一种方式是定义一个DateComponent可用于整个应用程序的组件。这样,{{ value | formatDate }}您将拥有<custom-date [date]="new Date()"></custom-date>.

在您的自定义日期组件中将如下所示

@Component({
  selector: 'custom-date',
  template: '<span>{{ formatedDate }}</span>'
})
export class DateComponent {
  @Input() date: string;
  timezone: string;
  formatedDate: string;
  constructor(private userService: UserService) {}

  ngOnInit(){
    this.timezone = this.userService.getTimeZone();
    this.updateValue();
    this.userService.onTimezoneChange()
      .subscribe(timezone => {
        this.timezone = timezone;
        this.updateValue();
      });
  }

  updateValue() {
    // Do your formatting the way you want
    this.formatedDate = moment(this.date).tz(this.timezone).format();
  }
}
于 2017-11-15T00:04:22.407 回答