Computed 属性 只触发一次

Computed property is only firing once

我有一个名为 screen-size 的服务,它有一个 属性 叫做 width。 此 属性 是 window 宽度的值,将在调整大小事件时更新。

这很好用。在一个组件中,我有一个计算的 属性,当这个值像这样变化时我想更新它...

nameStyle: computed('screenSizeService.width', function()
{
    console.log('in computed');
    return this.getFontSize(2.5, 2, null, null, this.$())
}),

开头只有运行宁一次,除非我这样做...

nameStyle: computed('screenSizeService.width', function()
{
    this.get('screenSizeService.width');
    console.log('in computed');
    return this.getFontSize(2.5, 2, null, null, this.$())
}),

那么它 运行 是正确的。 nameStyle的取值与屏幕宽度没有直接关系,而是随着屏幕宽度变化而变化的容器宽度。

这就是我从屏幕宽度读取的原因。

为什么我需要获取值才能使其工作?为什么它不只是根据它的变化和运行那个函数来计算?

我将尝试解释案例并尝试提出一些替代解决方案。

说明

Ember Guides 说:

Injected properties are lazy loaded; meaning the service will not be instantiated until the property is explicitly called.

因此,如果您的应用程序不使用某个服务,则在您的应用程序开始使用该服务之前,该服务不会被实例化。

此外,如果您不显式调用 组件中的服务,您的组件将保留代理对象,直到您第一次 call/usage 服务。而这个代理并不是真正的服务对象。

因此在组件的第一次渲染中,由于您不使用 screenSizeService,您将继续使用代理对象。所以当真实对象发生变化时,您的计算无法重新计算。

但是当您 use/call 该服务时,您将开始使用真实对象,因此您的计算将能够绑定到真实服务对象的更改。在您的第二个代码中,此 touch 发生在 this.get('screenSizeService.width'); 行。

替代解决方案

  1. 第一个选择是:在组件的 init/willRender 等挂钩中访问服务。如:
  init() {
    this._super(...arguments);
    // The following line added to initialize the service reference
    this.get('screenSizeService.width');
  }
  1. 第二种选择是:使用events。参见 Evented API 实际上,如果您不需要使用某项服务 属性,但您需要接收来自该服务的通知;那么events就可以很好地适应

在你的组件中你可以定义:

  init() {
    this._super(...arguments);
    this.get('screenSizeService').on('screenSizeChanged', ()=>{
      this.set('nameStyle', this.getFontSize(2.5, 2, null, null, this.$()))
    })
  }

并且在您的服务中,您需要通过以下方式触发它:this.trigger('screenSizeChanged') 每当宽度值发生变化时。