Haunted — это библиотека для создания веб-компонентов с использованием реактивного подхода, вдохновлённого React Hooks, но с полной интеграцией в стандартные Custom Elements. Обработка событий в Haunted строится на сочетании нативной модели событий браузера и реактивной системы состояний.
События в Haunted чаще всего привязываются к элементам через
атрибуты с префиксом on, аналогично JSX в
React.
import { html, component } from 'haunted';
function Counter() {
let count = 0;
const increment = () => count++;
return html`
<div>
<p>Счётчик: ${count}</p>
<button @click=${increment}>Увеличить</button>
</div>
`;
}
customElements.define('my-counter', component(Counter));
@ перед названием события (@click)
является синтаксическим сахаром Haunted для
addEventListener.useState или изменение наблюдаемых
значений.Haunted поддерживает привычный реактивный паттерн с хуками. Для
управления событиями чаще всего используют useState:
import { html, component, useState } from 'haunted';
function Toggle() {
const [active, setActive] = useState(false);
return html`
<button @click=${() => setActive(!active)}>
${active ? 'Включено' : 'Выключено'}
</button>
`;
}
customElements.define('my-toggle', component(Toggle));
Ключевые моменты:
useState создаёт реактивное состояние, которое
автоматически перерисовывает компонент при изменении.setActive,
обеспечивая синхронное обновление интерфейса.Иногда необходимо передать аргументы в обработчик. В Haunted это делается через замыкания:
function List() {
const items = ['Apple', 'Banana', 'Cherry'];
const handleClick = (item) => () => console.log(item);
return html`
<ul>
${items.map(item => html`
<li @click=${handleClick(item)}>${item}</li>
`)}
</ul>
`;
}
customElements.define('my-list', component(List));
Haunted позволяет создавать и отправлять кастомные события, которые могут быть пойманы родительскими компонентами или другими элементами DOM.
function Child() {
const notify = () => {
const event = new CustomEvent('notify', {
detail: { message: 'Привет из дочернего компонента' },
bubbles: true,
composed: true
});
dispatchEvent(event);
};
return html`<button @click=${notify}>Отправить событие</button>`;
}
customElements.define('child-component', component(Child));
function Parent() {
const handleNotification = (e) => console.log(e.detail.message);
return html`<child-component @notify=${handleNotification}></child-component>`;
}
customElements.define('parent-component', component(Parent));
bubbles: true и composed: true позволяют
событию подниматься по дереву DOM и пересекать границы Shadow DOM.detail используется для передачи данных вместе с
событием.Haunted хорошо интегрируется с формами, позволяя управлять состоянием ввода:
import { useState } from 'haunted';
function FormExample() {
const [value, setValue] = useState('');
const handleInput = (e) => setValue(e.target.value);
const handleSubmit = (e) => {
e.preventDefault();
console.log('Отправлено:', value);
};
return html`
<form @submit=${handleSubmit}>
<input type="text" .value=${value} @input=${handleInput} />
<button type="submit">Отправить</button>
</form>
`;
}
customElements.define('form-example', component(FormExample));
.value обозначает
связывание свойства, а не атрибута.@input обеспечивает реактивное обновление состояния при
каждом изменении текста.preventDefault() отменяет стандартное поведение
формы.html шаблона.useCallback нет необходимости, так как
Haunted перерисовывает только при изменении состояния, а не на каждую
мутацию DOM.Любое нативное событие DOM можно использовать напрямую. Например,
mouseenter, keydown, focus:
function HoverComponent() {
const [hovered, setHovered] = useState(false);
return html`
<div
@mouseenter=${() => setHovered(true)}
@mouseleave=${() => setHovered(false)}
>
${hovered ? 'Наведение' : 'Не наведено'}
</div>
`;
}
customElements.define('hover-component', component(HoverComponent));
Обработка событий в Haunted строится на комбинации реактивных состояний, замыканий и стандартной модели событий DOM, что позволяет создавать гибкие, производительные и легко поддерживаемые компоненты.