Haunted — это легковесная библиотека для создания веб-компонентов с использованием реактивного подхода, вдохновлённого React Hooks. При работе с крупными проектами часто возникает необходимость интегрировать Haunted в уже существующий код, написанный на чистом JavaScript, jQuery или других фреймворках. В таких случаях ключевыми задачами становятся: постепенное внедрение компонентов, управление состоянием и взаимодействие с DOM.
Haunted работает через веб-компоненты, что обеспечивает совместимость с любым HTML. Для добавления Haunted-компонента в старый проект достаточно создать кастомный элемент:
import { html, component } from 'haunted';
function Counter({ initial = 0 }) {
const [count, setCount] = useState(initial);
return html`
<div>
<p>Счётчик: ${count}</p>
<button @click=${() => setCount(count + 1)}>Увеличить</button>
</div>
`;
}
customElements.define('my-counter', component(Counter));
После регистрации элемента <my-counter> можно
вставлять его в любую часть HTML:
<div id="legacy-section">
<my-counter initial="5"></my-counter>
</div>
Важно отметить, что Haunted-компоненты не требуют перезаписи существующего DOM. Они полностью инкапсулируют своё поведение и состояние, минимизируя конфликт с legacy-кодом.
Haunted-компоненты принимают props, которые могут быть установлены через атрибуты HTML или через JavaScript. Атрибуты автоматически преобразуются в строковые значения, поэтому для чисел или объектов рекомендуется использовать передачу через свойства:
const counterElement = document.createElement('my-counter');
counterElement.initial = 10; // свойство, а не атрибут
document.body.appendChild(counterElement);
Использование свойств позволяет безопасно передавать сложные структуры данных, такие как массивы и объекты, что часто требуется при интеграции с legacy-приложениями.
В проектах, где активно используется jQuery, Haunted-компоненты можно вставлять и управлять ими через стандартные jQuery-методы:
$('#legacy-section').append('<my-counter></my-counter>');
const counterElement = $('#legacy-section my-counter')[0];
counterElement.initial = 3;
Haunted не конфликтует с jQuery, так как работает с shadow DOM или инкапсулированным рендером, что предотвращает нежелательные изменения внешнего DOM.
Haunted поддерживает хуки, такие как useState и
useEffect, что позволяет создавать динамические компоненты
без вмешательства в legacy-код. Для синхронизации состояния с внешним
миром используют кастомные события:
function Counter({ initial = 0 }) {
const [count, setCount] = useState(initial);
useEffect(() => {
const event = new CustomEvent('countChanged', { detail: count });
dispatchEvent(event);
}, [count]);
return html`
<div>
<p>Счётчик: ${count}</p>
<button @click=${() => setCount(count + 1)}>Увеличить</button>
</div>
`;
}
document.addEventListener('countChanged', e => {
console.log('Новое значение счётчика:', e.detail);
});
Такой подход позволяет поддерживать двунаправленное взаимодействие между Haunted-компонентами и существующими частями приложения.
Если проект использует устаревшие SPA-фреймворки (например, Backbone или старую версию Angular), Haunted можно интегрировать постепенно, создавая обёртки:
function mountHaunted(selector) {
const container = document.querySelector(selector);
if (!container) return;
const counter = document.createElement('my-counter');
container.appendChild(counter);
}
mountHaunted('#app-sidebar');
Это позволяет внедрять новые компоненты без переписывания всего приложения и минимизирует риски регрессий.
Haunted-компоненты поддерживают Shadow DOM, что обеспечивает изоляцию стилей. Для интеграции с существующим CSS можно:
component(fn, { useShadowDOM: false })).html и
css:const style = html`
<style>
p { color: blue; font-weight: bold; }
button { padding: 5px 10px; }
</style>
`;
return html`
${style}
<p>Счётчик: ${count}</p>
<button @click=${() => setCount(count + 1)}>+</button>
`;
Для интеграции с существующими событиями используют прослушку DOM-событий и передачу данных через props или события:
document.getElementById('legacy-button').addEventListener('click', () => {
const counter = document.querySelector('my-counter');
counter.initial += 1; // обновление состояния Haunted-компонента
});
Таким образом, Haunted может функционировать как реактивная часть старого интерфейса, не нарушая привычные процессы.
В проектах с Redux, MobX или другими глобальными стор-менеджерами Haunted может подписываться на изменения:
import store from './legacy-store';
function Counter() {
const [count, setCount] = useState(store.getState().counter);
useEffect(() => {
const unsubscribe = store.subscribe(() => setCount(store.getState().counter));
return unsubscribe;
}, []);
return html`<p>Счётчик: ${count}</p>`;
}
Такой подход позволяет плавно подключать Haunted к существующей архитектуре управления состоянием, обеспечивая согласованность между новым и старым кодом.