Синтаксис lit-html

Haunted — это библиотека для создания веб-компонентов на базе функциональных компонентов в стиле React, но с минимальным весом и использованием стандартного API Web Components. Она тесно интегрируется с библиотекой lit-html, которая отвечает за декларативное создание шаблонов HTML с возможностью реактивного обновления. Понимание синтаксиса lit-html является ключевым для эффективного использования Haunted.


Шаблоны html и интерполяция данных

В основе lit-html лежит тег-функция html, которая позволяет создавать шаблоны HTML с поддержкой динамических данных. Синтаксис следующий:

import { html, render } from 'lit-html';

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

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

  • Шаблон создается через html`...` — это тег-функция, а не обычный шаблонный литерал.
  • Вставка динамических значений выполняется через ${...}.
  • Lit-html отслеживает изменения данных и минимально обновляет DOM, изменяя только изменившиеся части.

Можно вставлять не только строки, но и целые элементы или другие шаблоны:

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

Атрибуты и свойства элементов

Lit-html различает атрибуты HTML и свойства элементов. Для установки свойства используется синтаксис .property=${value}:

const checked = true;
html`<input type="checkbox" .checked=${checked}>`;

Для установки атрибута используется синтаксис attr=${value}:

const id = 'input1';
html`<input id=${id}>`;

Для событий используется префикс @:

html`<button @click=${() => console.log('Клик')}>Нажми</button>`;

Важно: использование правильного префикса предотвращает конфликт между атрибутами, свойствами и обработчиками событий.


Управление условным рендерингом

Для условного рендеринга в lit-html применяются стандартные JavaScript конструкции. Наиболее часто используют тернарный оператор или логическое &&:

const isLoggedIn = true;

const template = html`
  ${isLoggedIn
    ? html`<p>Добро пожаловать!</p>`
    : html`<p>Пожалуйста, войдите в систему.</p>`}
`;

Для сложных условий удобно выделять шаблоны в отдельные функции:

const greetingTemplate = (user) => html`
  ${user ? html`<p>Привет, ${user}!</p>` : html`<p>Привет, гость!</p>`}
`;

Итерации и списки

Для рендеринга списков используется метод map, возвращающий массив шаблонов:

const todos = [
  { text: 'Купить молоко', done: false },
  { text: 'Написать статью', done: true },
];

const todoTemplate = html`
  <ul>
    ${todos.map(todo => html`
      <li class=${todo.done ? 'done' : ''}>${todo.text}</li>
    `)}
  </ul>
`;

Оптимизация обновлений: Lit-html использует keyed updates только при использовании функции repeat из пакета lit-html/directives/repeat.js, что важно для динамических списков.


Директивы lit-html

Директивы позволяют расширять стандартный синтаксис шаблонов. Среди основных:

  • repeat — для оптимизированного рендеринга списков.
  • ifDefined — для условной установки атрибутов.
  • guard — предотвращает ненужное пересоздание шаблонов при неизменных данных.
  • asyncAppend и asyncReplace — для работы с потоками данных.

Пример использования repeat:

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

const items = [
  { id: 1, name: 'One' },
  { id: 2, name: 'Two' }
];

html`
  <ul>
    ${repeat(items, item => item.id, item => html`<li>${item.name}</li>`)}
  </ul>
`;

Первый аргумент — массив данных, второй — функция для ключа (key), третий — функция для генерации шаблона элемента.


Встраивание других шаблонов

Шаблоны можно вкладывать друг в друга для модульного построения интерфейсов:

const card = (title, content) => html`
  <div class="card">
    <h3>${title}</h3>
    <p>${content}</p>
  </div>
`;

html`
  <div>
    ${card('Заголовок 1', 'Содержимое 1')}
    ${card('Заголовок 2', 'Содержимое 2')}
  </div>
`;

Такой подход повышает читаемость кода и упрощает поддержку больших компонентов.


Рендеринг в Haunted

В Haunted для отображения функциональных компонентов используется хук useEffect совместно с html и render. Пример минимального компонента:

import { component, html, useState } from 'haunted';

function Counter() {
  const [count, setCount] = useState(0);

  return html`
    <div>
      <p>Счёт: ${count}</p>
      <button @click=${() => setCount(count + 1)}>Увеличить</button>
    </div>
  `;
}

customElements.define('my-counter', component(Counter));

Особенности взаимодействия Haunted с lit-html:

  • Возвращаемый html из функционального компонента обновляется автоматически при изменении состояния.
  • События и свойства компонентов связываются через стандартные синтаксические конструкции lit-html.
  • Композиция компонентов проста, поскольку любой шаблон lit-html можно использовать внутри другого шаблона.

Резюме синтаксиса

  1. Шаблонные литералы — основной способ создания разметки: html`<p>${data}</p>`.
  2. Динамические данные вставляются через ${...}.
  3. Свойства и атрибуты различаются: .property=${value}, attr=${value}.
  4. События обрабатываются через @event=${handler}.
  5. Условный рендеринг — через тернарный оператор, логическое && или отдельные функции.
  6. Списки и итерации — через map или директиву repeat.
  7. Композиция шаблонов повышает модульность и читаемость.
  8. Интеграция с Haunted позволяет автоматически обновлять DOM при изменении состояния компонента.

Синтаксис lit-html сочетает лаконичность с высокой производительностью, а его грамотное использование в Haunted обеспечивает лёгкое создание динамических и реактивных веб-компонентов.