Haunted — это библиотека для создания веб-компонентов с реактивностью, вдохновлённая концепциями React, но использующая нативные Web Components. Одной из ключевых возможностей при работе с веб-компонентами является обработка и генерация пользовательских событий, что позволяет компонентам взаимодействовать друг с другом и с родительскими элементами без прямого связывания через свойства или методы.
В DOM существует встроенный механизм событий. Пользовательские
события создаются с помощью конструктора CustomEvent:
const event = new CustomEvent('my-event', {
detail: { message: 'Hello' },
bubbles: true,
composed: true
});
element.dispatchEvent(event);
Пояснение параметров:
detail — объект с данными, которые передаются
слушателю.bubbles — указывает, будет ли событие всплывать через
DOM.composed — позволяет событию пройти через shadow DOM
границы компонента.В Haunted этот подход используется в сочетании с хуками и функциональными компонентами для создания реактивных и интерактивных компонентов.
dispatchEvent внутри Haunted-компонентаФункциональный компонент в Haunted — это обычная функция, которая
возвращает шаблон с помощью html из haunted.
Для диспатча события внутри компонента нужно получить ссылку на корневой
элемент. Обычно используют useRef или стандартный
this в классовых Web Components. Пример с функциональным
компонентом:
import { html, component, useRef } from 'haunted';
function Button({ label }) {
const buttonRef = useRef();
const handleClick = () => {
const event = new CustomEvent('button-click', {
detail: { label },
bubbles: true,
composed: true
});
buttonRef.current.dispatchEvent(event);
};
return html`
<button @click=${handleClick} ref=${buttonRef}>${label}</button>
`;
}
customElements.define('my-button', component(Button));
Ключевые моменты:
bubbles: true позволяет родительскому
компоненту реагировать на событие.composed: true обеспечивает доступ события из-за
теневого DOM, что важно для скрытых компонентов.Обычно пользовательские события используют для взаимодействия между компонентами:
function Parent() {
const handleButtonClick = (e) => {
console.log('Нажата кнопка с меткой:', e.detail.label);
};
return html`
<my-button @button-click=${handleButtonClick} label="Click me"></my-button>
`;
}
customElements.define('my-parent', component(Parent));
button-click всплывает от дочернего компонента
к родителю.detail доступны обработчику.События могут использоваться для передачи результатов асинхронных операций:
function AsyncButton({ label }) {
const buttonRef = useRef();
const handleClick = async () => {
const result = await fetchData();
const event = new CustomEvent('data-loaded', {
detail: { result },
bubbles: true,
composed: true
});
buttonRef.current.dispatchEvent(event);
};
return html`<button @click=${handleClick} ref=${buttonRef}>${label}</button>`;
}
Пояснения:
data-loaded и обработать
результат без прямого вызова функции дочернего компонента.Haunted позволяет комбинировать shadow DOM с событиями. Понимание
параметров bubbles и composed критично:
| Параметр | Значение | Эффект |
|---|---|---|
bubbles |
true | Событие поднимается вверх по DOM до родителя |
bubbles |
false | Событие ограничено элементом, который его диспатчит |
composed |
true | Событие проходит через shadow DOM границы |
composed |
false | Событие ограничено shadow DOM, не достигает внешнего DOM |
Комбинации этих параметров позволяют контролировать видимость событий и предотвращать нежелательные утечки данных между компонентами.
detail для
передачи данных вместо изменения глобальных состояний.bubbles: true и
composed: true для событий, которые должны быть
доступны родителю.@event-name=${handler}, что соответствует привычной
реактивной модели Haunted.function TodoItem({ task }) {
const itemRef = useRef();
const toggleDone = () => {
const event = new CustomEvent('toggle-task', {
detail: { taskId: task.id },
bubbles: true,
composed: true
});
itemRef.current.dispatchEvent(event);
};
return html`
<div ref=${itemRef}>
<input type="checkbox" @change=${toggleDone} ?checked=${task.done} />
<span>${task.name}</span>
</div>
`;
}
function TodoList({ tasks }) {
const handleToggle = (e) => {
const id = e.detail.taskId;
console.log('Переключить задачу с id:', id);
// Логика обновления состояния списка задач
};
return html`
<div @toggle-task=${handleToggle}>
${tasks.map(task => html`<todo-item .task=${task}></todo-item>`)}
</div>
`;
}
customElements.define('todo-item', component(TodoItem));
customElements.define('todo-list', component(TodoList));
TodoItem диспатчит событие при
изменении состояния.TodoList обрабатывает событие и обновляет
список.Пользовательские события в Haunted создают мощный механизм взаимодействия между компонентами, позволяя реализовать чистую реактивную архитектуру, где данные и события проходят через явно определённые каналы, а компоненты остаются автономными.