HTML Templates

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


Определение шаблонов

В Haunted шаблон обычно создаётся с помощью функции html, импортируемой из самой библиотеки:

import { html, component } from 'haunted';

Функция html позволяет описывать структуру DOM с использованием литеральных шаблонов (template literals). Всё, что помещено внутрь `html```, превращается в реактивный шаблон, который обновляется при изменении состояния компонента.

Пример простого шаблона:

const MyComponent = () => {
  return html`
    <div class="container">
      <h1>Привет, Haunted!</h1>
      <p>Состояние компонента обновляется автоматически.</p>
    </div>
  `;
};

Здесь создаётся базовый DOM-структурированный блок, который при рендеринге вставляется в shadow DOM компонента.


Вставка динамических данных

Главная сила Haunted в том, что шаблоны могут включать динамические выражения внутри ${}. Любая переменная, функция или реактивное значение может быть вставлено непосредственно в шаблон:

import { useState } from 'haunted';

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

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

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

  • Любое изменение count автоматически обновит текст в <p>.
  • Атрибуты DOM также можно динамически задавать:
<input type="text" value="${count}" />

Реактивность шаблонов

Haunted обеспечивает тонкую реактивность: обновляются только те части DOM, которые реально изменились. Это достигается через «разметку шаблона» и механизм morphing DOM, где библиотека сравнивает старый и новый виртуальный DOM.

  • Если внутри шаблона используется массив элементов, его удобно обрабатывать с помощью .map():
const List = ({ items }) => html`
  <ul>
    ${items.map(item => html`<li>${item}</li>`)}
  </ul>
`;

Каждый элемент массива превращается в отдельный DOM-узел. При изменении items Haunted обновляет только необходимые <li>, не трогая остальной DOM.


Управление событиями

Шаблоны Haunted позволяют назначать обработчики событий через синтаксис @event:

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

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

  • Используется прямая ссылка на функцию, без .addEventListener.
  • Обработчики автоматически привязываются к shadow DOM компонента.
  • Можно передавать аргументы, используя стрелочные функции или замыкания.

Использование условной логики

Внутри шаблонов можно применять условные выражения напрямую:

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

Такой подход минимизирует необходимость вручную управлять видимостью элементов через display: none или removeChild.


Шаблоны и стили

Haunted позволяет вставлять CSS прямо в шаблон через <style>:

const StyledComponent = () => html`
  <style>
    p {
      color: blue;
      font-weight: bold;
    }
  </style>
  <p>Стили применяются только внутри этого компонента.</p>
`;
  • Стили из <style> ограничены shadow DOM, что предотвращает утечку CSS на страницу.
  • Можно использовать динамические значения для CSS:
const DynamicColor = ({ color }) => html`
  <p style="color: ${color}">Текст с динамическим цветом</p>
`;

Композиция шаблонов

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

const Item = ({ name }) => html`<li>${name}</li>`;

const ItemList = ({ items }) => html`
  <ul>
    ${items.map(item => html`${Item({ name: item })}`)}
  </ul>
`;

Такой подход поддерживает переиспользуемость и декларативный стиль кода, сохраняя реактивность на уровне вложенных компонентов.


Оптимизация больших шаблонов

Для больших интерфейсов рекомендуется:

  • Разбивать шаблон на мелкие функции, каждая из которых возвращает `html```.
  • Использовать key при работе с массивами для минимизации перестроения DOM.
  • Избегать глубоких вложенных вычислений внутри ${}, чтобы ускорить рендеринг.

Пример с ключами:

${items.map(item => html`<li key=${item.id}>${item.name}</li>`)}

Заключение по шаблонам

HTML-шаблоны в Haunted предоставляют гибкую систему декларативного описания интерфейсов, где:

  • Данные и разметка тесно связаны.
  • Реактивность встроена и оптимизирована.
  • Поддерживаются события, стили и условная логика прямо в шаблоне.
  • Композиция и переиспользуемость позволяют строить крупные компоненты без потери производительности.

Шаблоны в Haunted формируют основу построения современного веб-компонента с минимальным количеством кода и высокой читаемостью.