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() — функция, которая возвращает
шаблон.component(MyComponent) — оборачивает функцию в
полноценный веб-компонент.useStateHaunted поддерживает реактивное управление состоянием через хук
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 — массив атрибутов, которые
отслеживаются библиотекой для обновления компонента при изменении
значений.Иногда необходимо встроить компонент в произвольный элемент 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 не ограничивает выбор стилей. Для локальной стилизации можно
использовать тег <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));
Особенности:
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, поддержка свойств и событий, а также возможность
ручного рендеринга делают библиотеку гибкой и удобной для построения
интерактивных веб-приложений.