Инициировать вычисляемое свойство при вставке элемента - PullRequest
0 голосов
/ 12 мая 2019

У меня есть проект 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');
}

Так что это слушает событие изменения размера и вычисляет каждый раз, когда оно изменяется.Это работает очень хорошо, за исключением случаев, когда он изначально загружается.

При первоначальной загрузке родительский объект, который проходит через него, не имеет ширины, поэтому не может рассчитать размер шрифта, пока размер страницы не изменится.

Вот мой сервис размера экрана:

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);
    }
}

Наконец, функция My 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 Ответ

1 голос
/ 12 мая 2019

Я бы порекомендовал использовать компонент вместо сервиса и обернуть ваш контент в этот компонент.Таким образом, вы сможете использовать didInsertElement hook.

Примерно так, исходя из вашего кода:

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';

...