LitElement: лучшая практика (или лучшая производительность) при создании многих правил пользовательских стилей против пары динамических c правил внутри крошечного веб-компонента? - PullRequest
1 голос
/ 07 января 2020

Итак, я работаю над очень маленьким веб-компонентом, который станет частью гораздо большей системы проектирования.

Я немного новичок в использовании веб-компонентов, но я знаю, что этот конкретный веб-компонент может использоваться много-много раз в одном макете.

Этот веб-компонент контролирует, насколько вертикальное пространство для размещения любых дочерних компонентов, которые передаются в него.

Анатомия компонента довольно проста:

import { LitElement, html, css, unsafeCSS, property, customElement } from 'lit-element';

export const spacingAmounts = {
  'x-small': css`4px`,
  'small': css`8px`,
  'medium': css`12px`,
  'large': css`16px`,
  'x-large': css`20px`,
  '2x-large': css`30px`,
  '3x-large': css`40px`,
  '4x-large': css`60px`,
  '5x-large': css`90px`,
  '6x-large': css`120px`,
};

const createSpacingStyleRules = (direction: 'top' | 'bottom') => {
  return Object.keys(spacingAmounts).map(s => {
    const amount = spacingAmounts[s];
    return css`
      :host([${unsafeCSS(direction)}="${unsafeCSS(s)}"]) {
        margin-${unsafeCSS(direction)}: ${unsafeCSS(amount)};
      }
    `;
  });
};

@customElement('gu-vertical-space')
export class GuVerticalSpace extends LitElement {
  @property() top: string;
  @property() bottom: string;

  static get styles() {
    const styles = [
      css`
        :host {
          display: block;
        }
      `,
      // ----------------------------------------------------------
      // @TODO:
      // test if it's better performance wise to either:
      //
      // 1 -  generate a verbose list of static styles for
      //      each instance of gu-vertical-space
      //  or
      // 2 -  generate a tiny amount of styles on the fly, 
      //      based on property inputs...
      // ----------------------------------------------------------
      // ...createSpacingStyleRules('top'),
      // ...createSpacingStyleRules('bottom'),
    ];
    return styles;
  }

  render() {
    const styles = [];
    if (this.top) {
      styles.push(css`
        :host([top="${unsafeCSS(this.top)}"]) {
          margin-top: ${spacingAmounts[this.top]}
        }
      `);
    }
    if (this.bottom) {
      styles.push(css`
        :host([bottom="${unsafeCSS(this.bottom)}"]) {
          margin-bottom: ${spacingAmounts[this.bottom]}
        }
      `);
    }
    return html`
      <style>${styles}</style>
      <slot></slot>
    `;
  }
}


Здесь есть два подхода для сопоставления предопределенных величин полей с верхней или нижней частью хоста веб-компонента.

В настоящее время активный подход состоит в том, чтобы просто динамически генерировать блок <style> внутри функции рендеринга, который содержит любые величины полей, определяемые свойствами ввода "top" или "bottom".

Другой подход, который я рассматриваю (хотя и закомментирован), - статически генерировать огромный список правил стилей - таким образом, избегая необходимости генерировать какие-либо вещи стиля динамического c внутри рендера ( ) функция, которая может быть анти-паттерном - если я правильно понимаю документы с освещенным элементом .

Может быть, мне не хватает более элегантного подхода? Я склоняюсь к нынешнему подходу, просто потому, что его легче понять - но любопытно, что думают другие!

1 Ответ

2 голосов
/ 09 января 2020

Как предположил Алан, гораздо более простым решением этой проблемы является использование css -переменных.

По сути, просто сопоставьте значения входного поля как css -вариантную в событии жизненного цикла connect () (или выполните рендеринг, если вы предполагаете, что реквизиты когда-либо изменятся после первоначального рендеринга) - и вызовите его день!

static get styles() {
  return css`
    :host {
      display: block;
      margin-top: var(--margin-top);
      margin-bottom: var(--margin-bottom);
    }
  `;
}

connectedCallback() {
  super.connectedCallback();
  this.style.setProperty(
    '--margin-top',
    this.top
      ? spacingAmounts[this.top]
      : 'unset'
  );
  this.style.setProperty(
    '--margin-bottom',
    this.bottom
      ? spacingAmounts[this.bottom]
      : 'unset'
  );
}
...