Работа с анимациями

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));

Ключевые моменты:

  • Начальное состояние элемента устанавливается через inline-стиль (opacity: 0).
  • После монтирования компонента через useEffect изменяется свойство opacity, что запускает CSS-анимацию.
  • Пустой массив зависимостей [] гарантирует выполнение эффекта один раз после монтирования.

Реактивные анимации через useState

Haunted позволяет комбинировать 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.
  • Анимация привязывается к изменению CSS-свойства transform.
  • Использование CSS-переходов обеспечивает высокую производительность и плавность.

Комбинация CSS-анимаций и Haunted-хуков

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));

Преимущества такого метода:

  • Анимация полностью управляется CSS.
  • Haunted обеспечивает лишь управление классами, что снижает нагрузку на JavaScript.
  • Легко комбинировать с реактивными состояниями через 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 синхронизирует анимацию с частотой обновления экрана.
  • Можно реализовать сложные временные функции и физические движения.
  • Haunted обеспечивает безопасное управление DOM, не создавая конфликтов с реактивной системой.

Практические рекомендации

  • Использовать CSS-переходы и анимации для простых эффектов, чтобы снизить нагрузку на процессор.
  • useEffect идеально подходит для запуска анимаций после монтирования компонентов.
  • useState позволяет связывать состояния и анимации, создавая интерактивные интерфейсы.
  • Для сложных или кастомных анимаций применять requestAnimationFrame или интеграцию с внешними библиотеками анимации.
  • Всегда учитывать очистку эффектов, если элемент может быть удалён из DOM, чтобы избежать утечек памяти.

Haunted предоставляет легковесный и гибкий механизм для управления анимациями, совмещая реактивное обновление состояния с производительными CSS-эффектами. Такой подход позволяет создавать динамичные, отзывчивые интерфейсы без избыточного кода.