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');
行。
替代解决方案
- 第一个选择是:在组件的 init/willRender 等挂钩中访问服务。如:
init() {
this._super(...arguments);
// The following line added to initialize the service reference
this.get('screenSizeService.width');
}
- 第二种选择是:使用
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')
每当宽度值发生变化时。
我有一个名为 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');
行。
替代解决方案
- 第一个选择是:在组件的 init/willRender 等挂钩中访问服务。如:
init() {
this._super(...arguments);
// The following line added to initialize the service reference
this.get('screenSizeService.width');
}
- 第二种选择是:使用
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')
每当宽度值发生变化时。