插入元素时触发计算属性

时间:2019-05-12 11:02:43

标签: javascript ember.js computed-properties

我有一个ember项目,该项目具有一项服务,该服务根据元素的宽度获取元素的正确字体大小。用于响应式缩放。

这是我的代码。

元素:

screenSizeService: service('screen-size'),
utilsService:      service('utils'),

portrait:  computed.readOnly('screenSizeService.portrait'),
landscape: computed.readOnly('screenSizeService.landscape'),

style: computed('screenSizeService.{width,height}', 'landscape', 'portrait', function()
{
    console.log('calculating');
    //Since the properties have to be consumed, get their values
    this.get('screenSizeService.width');
    this.get('screenSizeService.height');

    //Params = scale if it's landscape, scale if it's portrait, min font size, max and the parent to watch the width of
    return this.getFontSize(1.2, 1.2, 30, 60, this.$();
}),

getFontSize(landscapeScale, portraitScale, min, max, parent)
{
    const scale = (this.get('landscape')) ? landscapeScale : portraitScale;
    const fontSize = this.get('utilsService').scaleFontSize(parent, scale, min, max);
    return htmlSafe('font-size: ' + fontSize + 'px');
}

因此,它侦听resize事件并在每次更改时进行计算。除了最初加载时,这确实非常有效。

在初次加载时,即时通讯通过的父级没有宽度,因此在调整页面大小之前无法计算其字体大小。

这是我的屏幕尺寸服务:

init()
{
    this._super(...arguments);
    this.get('resizeService').on('resize', this, this.screenSizeChange);
    this.screenSizeChange();
},

willDestroyElement()
{
    this._super(...arguments);
    this.get('resizeService').off('resize', this, this.screenSizeChange);
},

screenSizeChange()
{
    const width  = window.innerWidth;
    const height = window.innerHeight;

    this.set('width',  width);
    this.set('height', height);

    if (width >= height && !this.get('landscape'))
    {
        this.set('landscape', true);
        this.set('portrait',  false);
    }

    if (height > width && !this.get('portrait'))
    {
        this.set('landscape', false);
        this.set('portrait',  true);
    }
}

最后,我的utils函数计算字体大小:

scaleFontSize(parent, scale, min, max)
{
    const parentWidth = (parent && parent.width()) ? parent.width() : null;
    if (!parentWidth) {return;}

    scale = scale || 1;
    min   = min   || 1;
    max   = max   || 1000;

    return Math.max(Math.min(parentWidth / (scale * 10), parseFloat(max)), parseFloat(min));
}

有人会知道一种可能的解决方法,以便它根据didInsertElement进行计算吗?

我尝试在didInsertElement上设置样式,但是在调整大小时它不会改变。我想是因为我将它设置了两次。

需要任何帮助

1 个答案:

答案 0 :(得分:1)

我建议使用组件而不是服务,并将您的内容包装在该组件中。这样,您将可以使用didInsertElement挂钩。

根据您的代码,类似这样的东西:

import Component from '@ember/component';
import $ from 'jquery';
import { computed } from '@ember/object';
import { inject as service } from '@ember/service';

export default Component.extend({
  utilsService: service('utils'),

  style: computed('landscape', 'portrait', function() {
    return this.getFontSize(1.2, 1.2, 30, 60, this.$();
  }),

  getFontSize(landscapeScale, portraitScale, min, max, parent) {
    const scale = this.get('landscape') ? landscapeScale : portraitScale;
    const fontSize = this
      .get('utilsService')
      .scaleFontSize(parent, scale, min, max);
    return htmlSafe('font-size: ' + fontSize + 'px');
  },

  didInsertElement() {
    this._super(...arguments);
    //Element inserted, do calculations
    this.screenSizeChange();
    //Add resize handler
    $(window).on('resize', this._resizeHandler);
  },

  willDestroyElement() {
    this._super(...arguments);
    //It's important to remove resize handler on destroy, to avoid possible issues
    $(window).off('resize', this._resizeHandler);
  },

  _resizeHandler: computed(function() {
    const that = this;

    return function() {
      that.screenSizeChange();
    };
  }),

  screenSizeChange() {
    const width  = window.innerWidth;
    const height = window.innerHeight;

    this.set('landscape', width >= height);
    this.set('portrait',  width < height);
  }
});

顺便说一句,如果它仅包含静态方法(简单函数),则不需要utils服务。您可以在utils下创建app目录并在其中存储实用程序功能,并在代码中进行import scaleFontSize from 'project-name/utils/scale-font-size';