Библиотека Haunted предоставляет минималистичный
способ создания веб-компонентов на базе Web Components
с реактивным состоянием, используя функциональный подход, схожий с React
Hooks. Компоненты Haunted представляют собой обычные функции,
возвращающие шаблоны HTML с помощью библиотеки
lit-html.
Для использования Haunted в проекте достаточно подключить библиотеку через CDN или установить через npm:
<script type="module">
import { html, render } from 'https://unpkg.com/lit-html?module';
import { component, useState, useEffect } from 'https://unpkg.com/haunted?module';
</script>
Или через npm:
npm install haunted lit-html
import { html, render } from 'lit-html';
import { component, useState, useEffect } from 'haunted';
Компонент Haunted — это функция, которая принимает объект
props и возвращает шаблон html:
function Counter({ initial = 0 }) {
const [count, setCount] = useState(initial);
return html`
<div>
<p>Счётчик: ${count}</p>
<button @click=${() => setCount(count + 1)}>Увеличить</button>
<button @click=${() => setCount(count - 1)}>Уменьшить</button>
</div>
`;
}
Ключевой особенностью является использование хуков
useState для хранения состояния и useEffect
для побочных эффектов. Компонент автоматически обновляется при изменении
состояния.
Чтобы компонент можно было использовать в HTML, его необходимо зарегистрировать как кастомный элемент:
customElements.define('my-counter', component(Counter));
После регистрации компонент можно использовать в HTML так же, как стандартный элемент:
<my-counter initial="10"></my-counter>
Особенности работы с атрибутами:
props.Haunted предоставляет набор хуков, аналогичных React, для управления состоянием и жизненным циклом:
useState(initialValue) — создание локального состояния
компонента.useEffect(effect, deps) — выполнение побочных эффектов
при изменении зависимостей.useRef(initialValue) — создание ссылки на DOM-элемент
или любое значение.useContext(Context) — получение значения из контекста,
если используется контекст.Пример с эффектами:
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));
Haunted поддерживает слоты, что позволяет вставлять произвольный HTML внутрь компонента:
function Card({ title }) {
return html`
<div class="card">
<h2>${title}</h2>
<slot></slot>
</div>
`;
}
customElements.define('my-card', component(Card));
Использование в HTML:
<my-card title="Пример карточки">
<p>Содержимое карточки передано через слот.</p>
</my-card>
Стили можно подключать несколькими способами:
<style> внутри шаблона:function StyledButton() {
return html`
<style>
button {
background-color: #3498db;
color: white;
border: none;
padding: 10px 20px;
cursor: pointer;
}
button:hover {
background-color: #2980b9;
}
</style>
<button>Нажми меня</button>
`;
}
customElements.define('styled-button', component(StyledButton));
События добавляются через синтаксис @event=${handler}.
Это работает как с пользовательскими событиями, так и с нативными:
function ClickLogger() {
const handleClick = (e) => console.log('Клик:', e.target);
return html`
<button @click=${handleClick}>Логировать клик</button>
`;
}
customElements.define('click-logger', component(ClickLogger));
Внутри обработчика можно изменять состояние компонента через хуки
useState.
Props компонента задаются как атрибуты HTML, а для динамического обновления состояния можно использовать:
useState автоматически перерисовывают компонент.Пример кастомного события:
function InputEmitter() {
const [value, setValue] = useState('');
const emitChange = () => {
const event = new CustomEvent('value-change', {
detail: value,
bubbles: true,
composed: true
});
dispatchEvent(event);
};
return html`
<input @input=${e => setValue(e.target.value)} />
<button @click=${emitChange}>Отправить</button>
`;
}
customElements.define('input-emitter', component(InputEmitter));
Использование в родительском элементе:
<input-emitter @value-change=${e => console.log(e.detail)}></input-emitter>
Компоненты Haunted обеспечивают:
Такой подход позволяет создавать как простые виджеты, так и сложные интерфейсы, сочетая преимущества функционального программирования и нативных возможностей браузера.