Haunted — это библиотека для создания веб-компонентов на базе функциональных реактивных подходов. Одной из сильных сторон Haunted является возможность управлять анимациями и состояниями элементов через реактивные хуки, что позволяет создавать плавные и производительные интерфейсы без необходимости сторонних библиотек.
useEffect для анимацийХук useEffect в Haunted применяется для выполнения
побочных эффектов после рендеринга компонента. Он идеально подходит для
запуска анимаций после добавления элемента в DOM.
import { html, component } from 'haunted';
import { useEffect } from 'haunted';
function FadeInDiv() {
useEffect(() => {
const div = document.querySelector('.fade');
div.style.transition = 'opacity 1s ease-in-out';
div.style.opacity = 1;
}, []);
return html`
<div class="fade" style="opacity:0">
Появляющийся текст
</div>
`;
}
customElements.define('fade-in-div', component(FadeInDiv));
Ключевые моменты:
opacity: 0).useEffect
изменяется свойство opacity, что запускает
CSS-анимацию.[] гарантирует выполнение
эффекта один раз после монтирования.useStateHaunted позволяет комбинировать useState с
CSS-переходами для создания реактивных анимаций, которые зависят от
состояния компонента.
import { html, component } from 'haunted';
import { useState, useEffect } from 'haunted';
function ToggleSlide() {
const [visible, setVisible] = useState(false);
useEffect(() => {
const div = document.querySelector('.slide');
div.style.transition = 'transform 0.5s ease-in-out';
div.style.transform = visible ? 'translateX(0)' : 'translateX(-100%)';
}, [visible]);
return html`
<button @click=${() => setVisible(!visible)}>Переключить</button>
<div class="slide" style="transform: translateX(-100%)">
Сдвигающийся блок
</div>
`;
}
customElements.define('toggle-slide', component(ToggleSlide));
Особенности подхода:
visible автоматически
инициирует обновление DOM.transform.Haunted отлично интегрируется с классическими CSS-анимациями через
@keyframes. Для этого можно использовать
useEffect для динамического добавления классов.
import { html, component } from 'haunted';
import { useEffect } from 'haunted';
function BounceDiv() {
useEffect(() => {
const div = document.querySelector('.bounce');
div.classList.add('animate');
}, []);
return html`
<div class="bounce">Прыгающий блок</div>
<style>
.bounce {
display: inline-block;
}
.animate {
animation: bounce 1s infinite;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-20px); }
}
</style>
`;
}
customElements.define('bounce-div', component(BounceDiv));
Преимущества такого метода:
useState.requestAnimationFrame для сложных анимацийДля более точного контроля над анимацией можно использовать
requestAnimationFrame внутри useEffect. Такой
подход позволяет создавать интерполяции и сложные физические
эффекты без сторонних библиотек.
import { html, component } from 'haunted';
import { useEffect } from 'haunted';
function SmoothMove() {
useEffect(() => {
const div = document.querySelector('.smooth');
let start = null;
function step(timestamp) {
if (!start) start = timestamp;
const progress = Math.min((timestamp - start) / 1000, 1);
div.style.transform = `translateX(${progress * 200}px)`;
if (progress < 1) {
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);
}, []);
return html`
<div class="smooth" style="transform: translateX(0);">Движущийся блок</div>
`;
}
customElements.define('smooth-move', component(SmoothMove));
Особенности метода:
requestAnimationFrame синхронизирует анимацию с
частотой обновления экрана.useEffect идеально подходит для запуска анимаций после
монтирования компонентов.useState позволяет связывать состояния и
анимации, создавая интерактивные интерфейсы.requestAnimationFrame или интеграцию с внешними
библиотеками анимации.Haunted предоставляет легковесный и гибкий механизм для управления анимациями, совмещая реактивное обновление состояния с производительными CSS-эффектами. Такой подход позволяет создавать динамичные, отзывчивые интерфейсы без избыточного кода.