Работа с lit-html

SkateJS — это легковесная библиотека для создания веб-компонентов на базе стандартов Custom Elements. Одним из наиболее эффективных способов работы с шаблонами в SkateJS является использование lit-html. Она обеспечивает декларативное построение DOM и реактивное обновление интерфейса без необходимости ручного управления элементами.

Для подключения lit-html в SkateJS необходимо импортировать функцию html из lit-html:

import { html, render } from 'lit-html';
import { define, Component } from 'skatejs';

Шаблон создается через функцию html:

const template = (name) => html`<p>Привет, ${name}!</p>`;

Здесь переменная name автоматически интегрируется в DOM. SkateJS позволяет использовать такой шаблон внутри метода render компонента, обеспечивая реактивное обновление.


Создание компонента с lit-html

В SkateJS компонент создается наследованием от Component:

class Greeting extends Component {
  static get props() {
    return {
      name: String
    };
  }

  renderCallback() {
    return html`<p>Привет, ${this.name}!</p>`;
  }
}

define('my-greeting', Greeting);

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

  • props задают свойства компонента, которые могут быть реактивными.
  • renderCallback() отвечает за генерацию DOM. Важно возвращать именно html шаблон lit-html.
  • SkateJS автоматически вызывает рендер при изменении реактивных свойств.

Обновление DOM при изменении свойств

Lit-html и SkateJS обеспечивают эффективное обновление DOM без полной перерисовки:

const greeting = document.querySelector('my-greeting');
greeting.name = 'Алексей';

В результате SkateJS вызывает renderCallback(), lit-html сравнивает старый и новый DOM и обновляет только изменившиеся узлы. Это делает обновления быстрыми и минимально ресурсоёмкими.


Вложенные шаблоны и условный рендеринг

Lit-html позволяет использовать вложенные шаблоны и условные конструкции:

renderCallback() {
  return html`
    <div>
      ${this.name ? html`<p>Привет, ${this.name}!</p>` : html`<p>Имя не задано</p>`}
      ${this._renderList()}
    </div>
  `;
}

_renderList() {
  const items = ['яблоко', 'банан', 'вишня'];
  return html`<ul>${items.map(item => html`<li>${item}</li>`)}</ul>`;
}

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

  • html можно использовать внутри функций для разделения шаблона на логические блоки.
  • Условные выражения (? :) позволяют динамически менять содержимое.
  • Массивы автоматически рендерятся как список элементов.

Работа с событиями

Lit-html поддерживает декларативное подключение событий через синтаксис @event:

renderCallback() {
  return html`
    <button @click=${this._handleClick}>Нажми меня</button>
  `;
}

_handleClick(event) {
  console.log('Клик по кнопке:', event.target);
}

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

  • События автоматически привязываются при рендере.
  • Не требуется ручное добавление слушателей через addEventListener.
  • SkateJS гарантирует корректное удаление обработчиков при обновлении DOM.

Статические и динамические атрибуты

Lit-html позволяет задавать как статические, так и динамические атрибуты:

renderCallback() {
  const disabled = this.name === '';
  return html`<input type="text" .value=${this.name} ?disabled=${disabled} />`;
}

Синтаксис:

  • .value=${this.name} — привязка свойства элемента.
  • ?disabled=${disabled} — условное добавление атрибута.

Эта модель упрощает синхронизацию состояния компонента с DOM.


Интеграция стилей

SkateJS совместно с lit-html позволяет легко включать стили:

renderCallback() {
  return html`
    <style>
      p {
        color: blue;
        font-weight: bold;
      }
    </style>
    <p>Привет, ${this.name}!</p>
  `;
}

Стили инкапсулируются внутри компонента, предотвращая конфликты с остальной страницей. Для сложных проектов рекомендуется использовать Shadow DOM, включаемый автоматически через SkateJS:

class StyledGreeting extends Component {
  static get useShadow() { return true; }

  renderCallback() {
    return html`
      <style>
        p { color: green; }
      </style>
      <p>${this.name}</p>
    `;
  }
}

Асинхронный рендеринг и данные из API

Lit-html позволяет интегрировать асинхронные данные:

class AsyncList extends Component {
  static get props() {
    return { items: Array };
  }

  async connectedCallback() {
    super.connectedCallback();
    const response = await fetch('https://api.example.com/items');
    this.items = await response.json();
  }

  renderCallback() {
    if (!this.items) return html`<p>Загрузка...</p>`;
    return html`<ul>${this.items.map(i => html`<li>${i.name}</li>`)}</ul>`;
  }
}

Примечания:

  • SkateJS следит за изменениями свойств и повторно вызывает renderCallback().
  • Lit-html обновляет только изменившиеся узлы, минимизируя перерисовку.

Итоговая структура эффективного компонента SkateJS с lit-html

  1. Импорт и подключение lit-html (html, render).
  2. Определение реактивных свойств через props.
  3. Использование renderCallback() для генерации шаблона.
  4. Декларативная привязка событий и атрибутов.
  5. Инкапсуляция стилей через Shadow DOM.
  6. Асинхронные данные и реактивные обновления.

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