Регистрация компонента

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


Создание компонента

В Haunted компонент создаётся с помощью функции component. Она принимает функцию с состояниями и возвращает HTML-шаблон, создаваемый через html из lit-html.

Пример базового компонента:

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>
  `;
}

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


Функция customElements.define

Для того чтобы браузер распознавал компонент как тег HTML, необходимо зарегистрировать его с помощью стандартного API Web Components:

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

Аргументы:

  1. 'my-counter' — имя нового кастомного элемента. Должно содержать хотя бы один дефис.
  2. component(Counter) — результат вызова component, который превращает функцию в полноценный веб-компонент.

После регистрации <my-counter></my-counter> можно использовать в любом месте DOM.


Параметры функции component

Функция component принимает второй необязательный аргумент — опции компонента:

component(fn, { observedAttributes, useShadowDOM = true })
  • observedAttributes — массив атрибутов, на изменения которых компонент должен реагировать. Атрибуты автоматически передаются в функцию компонента.
  • useShadowDOM — логическое значение, определяющее использование Shadow DOM (по умолчанию true).

Пример с атрибутами:

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

customElements.define(
  'my-greeting',
  component(Greeting, { observedAttributes: ['name'] })
);

Теперь изменение атрибута name у элемента <my-greeting> автоматически обновит компонент:

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

Shadow DOM и стилизация

По умолчанию Haunted компоненты используют Shadow DOM, что изолирует стили компонента от глобальных CSS.

Если нужно отключить Shadow DOM, например для интеграции с существующей разметкой:

customElements.define(
  'no-shadow-component',
  component(MyComponent, { useShadowDOM: false })
);

В этом случае все стили наследуются из внешнего контекста, и компонент полностью рендерится в light DOM.


Реактивные свойства

Haunted автоматически отслеживает изменения состояния через useState, но также можно использовать атрибуты и свойства элемента.

Пример с синхронизацией атрибутов и состояния:

function Toggle({ active }) {
  const [isActive, setActive] = useState(active === 'true');

  return html`
    <button @click=${() => setActive(!isActive)}>
      ${isActive ? 'Включено' : 'Выключено'}
    </button>
  `;
}

customElements.define(
  'my-toggle',
  component(Toggle, { observedAttributes: ['active'] })
);

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


Динамическая регистрация компонентов

Компоненты можно регистрировать условно или динамически, проверяя наличие уже существующего элемента:

if (!customElements.get('dynamic-counter')) {
  customElements.define('dynamic-counter', component(Counter));
}

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


Важные моменты

  • Имя кастомного элемента обязательно должно содержать дефис.
  • Функция компонента должна возвращать html из Haunted.
  • Использование Shadow DOM позволяет изолировать стили, но может быть отключено через useShadowDOM.
  • Атрибуты, указанные в observedAttributes, автоматически отслеживаются и передаются компоненту.

Регистрация компонента — фундаментальный шаг для работы с Haunted, от которого зависит корректная реактивность, изоляция стилей и возможность повторного использования в любом месте приложения.