Haunted — это библиотека для создания веб-компонентов на базе стандартов Web Components и Hooks в стиле React. Она позволяет создавать реактивные пользовательские элементы с минимальной обвязкой. Одной из важных задач при работе с компонентами является измерение DOM-элементов для управления их размером, положением и поведением в интерфейсе.
Haunted использует хуки, похожие на React. Для работы с DOM внутри
компонента применяются хуки useRef и
useEffect.
import { html, component } from 'haunted';
import { useRef, useEffect, useState } from 'haunted';
function MyComponent() {
const elementRef = useRef(null);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
useEffect(() => {
const el = elementRef.current;
if (el) {
const { width, height } = el.getBoundingClientRect();
setDimensions({ width, height });
}
}, []);
return html`
<div ref=${elementRef} style="background: lightgray;">
Ширина: ${dimensions.width}px, Высота: ${dimensions.height}px
</div>
`;
}
customElements.define('my-component', component(MyComponent));
Ключевые моменты:
useRef создаёт ссылку на DOM-элемент.useEffect выполняется после первого рендера компонента,
что позволяет безопасно обращаться к DOM.getBoundingClientRect() возвращает размеры и координаты
элемента.Для отслеживания изменения размера элемента удобно использовать
ResizeObserver. Он позволяет реагировать на изменение
размеров без постоянного опроса DOM.
useEffect(() => {
const el = elementRef.current;
if (!el) return;
const observer = new ResizeObserver(entries => {
for (let entry of entries) {
const { width, height } = entry.contentRect;
setDimensions({ width, height });
}
});
observer.observe(el);
return () => observer.disconnect();
}, []);
Особенности использования:
ResizeObserver асинхронно уведомляет о любых изменениях
размеров.useEffect обязательно возвращать функцию очистки,
чтобы избежать утечек памяти.Иногда требуется не только размеры, но и положение элемента на
странице. Для этого используют getBoundingClientRect():
useEffect(() => {
const el = elementRef.current;
if (!el) return;
const updatePosition = () => {
const { top, left } = el.getBoundingClientRect();
setPosition({ top, left });
};
updatePosition();
window.addEventListener('scroll', updatePosition);
window.addEventListener('resize', updatePosition);
return () => {
window.removeEventListener('scroll', updatePosition);
window.removeEventListener('resize', updatePosition);
};
}, []);
Примечания:
useEffect добавляется обработка событий
scroll и resize.Измеренные значения можно использовать для динамического изменения стилей через CSS-переменные:
return html`
<div
ref=${elementRef}
style="--width: ${dimensions.width}px; --height: ${dimensions.height}px;"
>
Контент
</div>
`;
Это позволяет создавать адаптивные компоненты без прямого изменения стилей через JS каждый раз.
useRef не вызывает повторный рендер при изменении
ссылки.ResizeObserver эффективнее setInterval для
отслеживания размеров.requestAnimationFrame, чтобы минимизировать layout
thrashing.ref для элемента.useEffect выполняется первое измерение.ResizeObserver для динамических
изменений.scroll и
resize.Такой подход обеспечивает реактивность компонента и позволяет гибко управлять его визуальным поведением в зависимости от размеров и позиции на странице.