Установка и начало работы

Установка библиотеки

Haunted — это лёгкая библиотека для создания веб-компонентов с использованием реактивного подхода, вдохновлённого React Hooks. Для начала работы с Haunted необходимо подключить библиотеку в проект. Существует несколько способов установки: через npm, yarn или с использованием CDN.

Через npm:

npm install haunted

Через yarn:

yarn add haunted

Подключение через CDN:

<script type="module">
  import { html, render, component, useState, useEffect } from 'https://unpkg.com/haunted/haunted.js?module';
</script>

Использование модульного подключения через <script type="module"> позволяет сразу применять функции библиотеки без необходимости сборки проекта с помощью инструментов вроде Webpack или Vite.


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

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

import { html, component } from 'haunted';

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

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

Здесь ключевые моменты:

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

Использование состояния с useState

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

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));

Особенности работы useState:

  • Первый элемент массива — текущее значение состояния.
  • Второй элемент — функция для обновления состояния. Любое изменение вызывает повторный рендер компонента.
  • Использование стрелочной функции в обработчике событий позволяет корректно изменять состояние без потери контекста.

Реактивные эффекты с useEffect

Для выполнения побочных действий, например, подписки на события или обращения к API, используется хук useEffect. Он вызывается после каждого рендера и может очищать эффекты при демонтировании компонента.

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

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => setSeconds(s => s + 1), 1000);
    return () => clearInterval(interval);
  }, []);

  return html`<p>Прошло секунд: ${seconds}</p>`;
}

customElements.define('my-timer', component(Timer));

Ключевые особенности useEffect:

  • Возвращаемая функция выполняется при размонтировании компонента.
  • Второй аргумент — массив зависимостей. Пустой массив [] означает, что эффект выполняется только один раз после первого рендера.
  • Любые изменения зависимостей вызывают повторное выполнение эффекта.

Передача и использование свойств

Haunted позволяет передавать свойства в компонент через атрибуты HTML и автоматически связывать их с состоянием компонента.

import { html, component } from 'haunted';

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

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

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

  • observedAttributes — массив атрибутов, которые отслеживаются библиотекой для обновления компонента при изменении значений.
  • Свойства, переданные в компонент, доступны как аргументы функции.
  • Любое изменение атрибута HTML автоматически вызывает рендер.

Рендеринг компонентов вручную

Иногда необходимо встроить компонент в произвольный элемент DOM без использования тега customElements.define. Для этого применяется функция render:

import { html, render } from 'haunted';

const root = document.getElementById('app');
const template = html`<p>Привет, Haunted!</p>`;

render(template, root);

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

  • render(template, container) — помещает шаблон в контейнер и автоматически обновляет DOM при повторных вызовах.
  • Позволяет использовать Haunted вне контекста веб-компонентов, например, для динамических вставок контента.

Стилизация компонентов

Haunted не ограничивает выбор стилей. Для локальной стилизации можно использовать тег <style> внутри шаблона:

import { html, component } from 'haunted';

function StyledBox() {
  return html`
    <style>
      div {
        background-color: lightblue;
        padding: 20px;
        border-radius: 10px;
      }
    </style>
    <div>Красивый блок</div>
  `;
}

customElements.define('styled-box', component(StyledBox));

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

  • Стили внутри шаблона ограничены этим компонентом и не влияют на глобальный CSS.
  • Можно использовать CSS-переменные для динамической стилизации на основе состояния.

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

Haunted поддерживает связывание событий через директиву @ перед названием события:

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

function Clicker() {
  const [text, setText] = useState('Нажми меня');

  return html`<button @click=${() => setText('Кнопка нажата')}>${text}</button>`;
}

customElements.define('clicker-button', component(Clicker));

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

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

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