Библиотеки компонентов

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

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

Компонент в Haunted создаётся как функция, возвращающая разметку с помощью html тег-функции. Основная структура компонента выглядит следующим образом:

import { html, component } from 'haunted';

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

customElements.define('my-component', component(MyComponent));

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

  • component() — функция, оборачивающая обычную функцию в полноценный веб-компонент.
  • html — шаблонная функция, аналог JSX, создающая виртуальное представление DOM.
  • Свойства компонента передаются через объект аргументов функции.

Реактивность с Hooks

Haunted поддерживает концепцию Hooks, знакомую по React. Основные Hooks включают:

  • useState — для локального состояния.
  • useEffect — для побочных эффектов.
  • useReducer — для более сложного управления состоянием.
  • useRef — для хранения ссылок на DOM-элементы или другие значения.

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

import { html, component, 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 — автоматическое обновление компонента при изменении состояния через useState.

Обработка событий

Haunted использует синтаксис @событие=${handler} для привязки обработчиков. Это заменяет стандартное addEventListener, позволяя писать компактный и читаемый код:

html`<button @click=${handleClick}>Нажми меня</button>`

handleClick — это функция, определённая внутри компонента или импортированная извне. Такая привязка автоматически очищается при размонтировании компонента, что предотвращает утечки памяти.

Передача свойств и атрибутов

Компоненты Haunted поддерживают реактивные свойства и атрибуты. Любое свойство, переданное компоненту, становится доступным через аргументы функции:

html`<my-component name="Иван"></my-component>`

Внутри компонента name будет доступен напрямую:

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

Свойства могут быть реактивными, что позволяет компоненту автоматически перерисовываться при их изменении:

const el = document.createElement('my-component');
el.name = 'Мария';
document.body.appendChild(el);

Комбинирование компонентов

Haunted позволяет создавать сложные интерфейсы из вложенных компонентов. Любой компонент можно использовать как обычный HTML-тег внутри другого компонента:

function App() {
  return html`
    <div>
      <my-counter></my-counter>
      <my-component name="Алексей"></my-component>
    </div>
  `;
}

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

Работа с Shadow DOM

Все компоненты Haunted по умолчанию используют Shadow DOM, что изолирует стили и структуру DOM от остальной страницы. Внутри компонента можно использовать стандартные CSS:

function StyledComponent() {
  return html`
    <style>
      p { color: blue; font-weight: bold; }
    </style>
    <p>Стилизованный текст</p>
  `;
}

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

Эффекты и жизненный цикл

Haunted поддерживает жизненный цикл через useEffect, аналогично React:

import { useEffect } from 'haunted';

function Timer() {
  const [time, setTime] = useState(0);

  useEffect(() => {
    const id = setInterval(() => setTime(t => t + 1), 1000);
    return () => clearInterval(id);
  }, []);

  return html`<p>Время: ${time}</p>`;
}
  • Функция useEffect выполняется после рендера.
  • Возвращаемая функция служит для очистки ресурсов, например таймеров или подписок.

Производительность и оптимизация

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

  • Делить интерфейс на мелкие компоненты.
  • Использовать useMemo для вычислений, зависящих от состояния.
  • Минимизировать количество inline-функций внутри шаблонов.

Интеграция с другими библиотеками

Haunted легко интегрируется с любой сторонней библиотекой JavaScript. Любой компонент можно обернуть вокруг стороннего виджета, используя useEffect для инициализации и очистки:

import someLibrary from 'some-library';

function WidgetWrapper({ options }) {
  const ref = useRef();

  useEffect(() => {
    const widget = someLibrary.init(ref.current, options);
    return () => widget.destroy();
  }, [options]);

  return html`<div ${ref}></div>`;
}

Расширяемость

Haunted позволяет создавать собственные Hooks, что облегчает повторное использование логики:

import { useState, useEffect } from 'haunted';

function useToggle(initial = false) {
  const [state, setState] = useState(initial);
  const toggle = () => setState(s => !s);
  return [state, toggle];
}

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


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