计算属性仅触发一次

时间:2019-04-28 13:03:52

标签: javascript ember.js

我有一个名为screen-size的服务,该服务具有一个称为width的属性。 此属性是窗口宽度的值,并将在调整大小事件时更新。

这很好。在组件中,我有一个计算属性,当此值更改时,我想更新该属性...

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的值与屏幕宽度没有直接关系,但是容器宽度会随着屏幕宽度的变化而改变。

这就是为什么我从屏幕宽度读取内容。

为什么我需要获取值才能使它起作用?为什么不从更改和运行该功能时开始计算呢?

1 个答案:

答案 0 :(得分:1)

我将尽力解释这种情况,并尝试提出一些替代解决方案。

说明

Ember Guides说:

  

注入的属性是延迟加载的;意味着在显式调用该属性之前,不会实例化该服务。

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

此外,如果您没有明确调用组件中的服务,则组件将保留代理对象,直到您第一次调用/使用该服务。而且该代理不是真正的服务对象。

因此,在组件的第一个渲染中,由于您不使用screenSizeService,因此将继续使用代理对象。因此,当真实对象更改时,您的计算结果将无法重新计算。

但是当您使用/调用该服务时,您将开始使用真实对象,因此您的计算对象将能够绑定到真实服务对象的更改。在您的第二个代码中,此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 实际上,如果您不需要使用services属性,但是您需要从该服务接收通知;那么events就可以很好地适应了。

您可以在组件中定义:

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

,并且在您的服务中,只要宽度值发生更改,您就需要使用this.trigger('screenSizeChanged')来触发它。

相关问题