Встроенные директивы

Фреймворк Lit предоставляет набор встроенных директив, которые позволяют управлять рендерингом шаблонов, оптимизировать производительность и создавать динамический контент. Директивы применяются внутри шаблонов, определяемых с помощью функции html, и обеспечивают контроль над структурой DOM, стилями и событиями.


repeat — рендеринг списков

Директива repeat используется для эффективного рендеринга массивов. Она особенно полезна при работе с большими списками, так как позволяет минимизировать количество операций с DOM за счет повторного использования существующих элементов.

import { html, LitElement } from 'lit';
import { repeat } from 'lit/directives/repeat.js';

class ItemList extends LitElement {
  static properties = {
    items: { type: Array }
  };

  render() {
    return html`
      <ul>
        ${repeat(
          this.items,
          item => item.id,
          item => html`<li>${item.name}</li>`
        )}
      </ul>
    `;
  }
}
customElements.define('item-list', ItemList);

Ключевые моменты:

  • Первый аргумент — массив данных.
  • Второй аргумент — функция, возвращающая уникальный ключ для элемента.
  • Третий аргумент — функция, возвращающая шаблон для каждого элемента массива.

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


ifDefined — условная подстановка атрибутов

Директива ifDefined позволяет вставлять атрибут только если значение не undefined. Это удобно при работе с динамическими атрибутами.

import { html, LitElement } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';

class ButtonLink extends LitElement {
  static properties = {
    href: { type: String }
  };

  render() {
    return html`
      <a href="${ifDefined(this.href)}">Ссылка</a>
    `;
  }
}
customElements.define('button-link', ButtonLink);

Если this.href равно undefined, атрибут href не будет добавлен к элементу. Это предотвращает ошибки и некорректное поведение ссылок.


guard — оптимизация перерисовки

Директива guard используется для предотвращения ненужной перерисовки сложных шаблонов. Она принимает массив зависимостей и шаблон, который будет перерендерен только при изменении зависимостей.

import { html, LitElement } from 'lit';
import { guard } from 'lit/directives/guard.js';

class ExpensiveRender extends LitElement {
  static properties = {
    data: { type: Array }
  };

  render() {
    return html`
      ${guard([this.data], () => html`
        <ul>
          ${this.data.map(item => html`<li>${item}</li>`)}
        </ul>
      `)}
    `;
  }
}
customElements.define('expensive-render', ExpensiveRender);

Особенности:

  • Перерисовка происходит только при изменении зависимостей.
  • Экономит ресурсы при работе с тяжелыми компонентами или большими массивами данных.

asyncAppend и asyncReplace — работа с асинхронными итераторами

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

  • asyncAppend добавляет новые элементы в конец списка без перезаписи существующих.
  • asyncReplace заменяет содержимое по мере поступления новых данных.
import { html, LitElement } from 'lit';
import { asyncAppend } from 'lit/directives/async-append.js';

class StreamList extends LitElement {
  static properties = {
    items: { type: Object } // асинхронный итератор
  };

  render() {
    return html`
      <ul>
        ${asyncAppend(this.items, item => html`<li>${item}</li>`)}
      </ul>
    `;
  }
}
customElements.define('stream-list', StreamList);

Это особенно полезно для потоковых данных, таких как WebSocket-сообщения или асинхронные API-запросы.


classMap и styleMap — динамическая привязка классов и стилей

Директивы classMap и styleMap позволяют управлять CSS-классами и inline-стилями на основе объекта.

import { html, LitElement } from 'lit';
import { classMap } from 'lit/directives/class-map.js';
import { styleMap } from 'lit/directives/style-map.js';

class StyledButton extends LitElement {
  static properties = {
    active: { type: Boolean },
    color: { type: String }
  };

  render() {
    const classes = { active: this.active, disabled: !this.active };
    const styles = { backgroundColor: this.color, padding: '10px' };

    return html`
      <button class="${classMap(classes)}" style="${styleMap(styles)}">
        Кнопка
      </button>
    `;
  }
}
customElements.define('styled-button', StyledButton);

Преимущества:

  • Упрощение управления состоянием UI.
  • Автоматическое обновление классов и стилей без ручного управления DOM.

live — синхронизация с реальными значениями

Директива live применяется для синхронизации значений форм с реальным состоянием, предотвращая нежелательные сбросы при обновлении шаблона.

import { html, LitElement } from 'lit';
import { live } from 'lit/directives/live.js';

class TextInput extends LitElement {
  static properties = {
    value: { type: String }
  };

  render() {
    return html`
      <input .value="${live(this.value)}">
    `;
  }
}
customElements.define('text-input', TextInput);

live гарантирует, что значение элемента формы не будет перезаписано, если оно уже изменено пользователем.


Другие полезные встроенные директивы

  • unsafeHTML — вставка HTML-кода из строки (с осторожностью, потенциально небезопасно).
  • ref — получение ссылки на элемент внутри шаблона.
  • until — отображение шаблона-заглушки до завершения промиса.

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


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