Анимация при монтировании

Atomico — библиотека для создания веб-компонентов на основе JavaScript с реактивным подходом. Одним из важных аспектов интерфейсной разработки является управление анимацией при монтировании компонентов. В Atomico это реализуется через сочетание реактивных хуков и API для работы с жизненным циклом компонента.

Хук useEffect для инициализации анимации

Для запуска анимации при появлении компонента используется стандартный хук useEffect. Основная задача — запустить анимацию один раз после того, как компонент будет добавлен в DOM.

import { c, useEffect, useRef } from "atomico";

function FadeInComponent() {
    const ref = useRef();

    useEffect(() => {
        const el = ref.current;
        if (!el) return;

        el.style.opacity = 0;
        el.style.transition = "opacity 0.5s ease-in-out";

        requestAnimationFrame(() => {
            el.style.opacity = 1;
        });
    }, []);

    return <div ref={ref}>Пример анимации при монтировании</div>;
}

customElements.define("fade-in-component", c(FadeInComponent));

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

  • useRef используется для получения ссылки на DOM-элемент.
  • requestAnimationFrame позволяет корректно применить CSS-транзишн после добавления элемента в DOM.
  • Анимация запускается только один раз за счёт пустого массива зависимостей в useEffect.

Работа с @keyframes и CSS-анимациями

Помимо прямого изменения стилей, Atomico поддерживает интеграцию с CSS-анимациями через keyframes. Это позволяет более гибко управлять сложными эффектами без JavaScript.

import { c, css } from "atomico";

const styles = css`
    @keyframes fade-in {
        from { opacity: 0; transform: translateY(20px); }
        to { opacity: 1; transform: translateY(0); }
    }

    :host {
        display: block;
        animation: fade-in 0.6s ease forwards;
    }
`;

function FadeInAnimation() {
    return <div>Анимация через CSS keyframes</div>;
}

FadeInAnimation.styles = styles;

customElements.define("fade-in-animation", c(FadeInAnimation));

Особенности:

  • :host позволяет применить анимацию ко всему компоненту.
  • Использование forwards сохраняет конечное состояние анимации после её завершения.
  • Можно комбинировать смещение, прозрачность и другие CSS-свойства для создания сложных эффектов.

Последовательные анимации нескольких элементов

Для компонентов с несколькими элементами, которые должны появляться поочередно, используется массив ссылок и задержка с setTimeout или библиотека anime.js.

import { c, useEffect, useRef } from "atomico";

function SequentialFade() {
    const refs = useRef([]);

    useEffect(() => {
        refs.current.forEach((el, i) => {
            if (!el) return;
            el.style.opacity = 0;
            el.style.transition = "opacity 0.4s ease";
            setTimeout(() => {
                el.style.opacity = 1;
            }, i * 200);
        });
    }, []);

    return (
        <div>
            {["Первый", "Второй", "Третий"].map((text, i) => (
                <div key={i} ref={el => (refs.current[i] = el)}>
                    {text}
                </div>
            ))}
        </div>
    );
}

customElements.define("sequential-fade", c(SequentialFade));

Особенности подхода:

  • Массив ссылок позволяет управлять каждым элементом отдельно.
  • Задержка через i * 200 создаёт эффект поочередного появления.
  • Подходит для списков, карточек и меню с анимацией.

Интеграция с библиотеками анимации

Atomico легко интегрируется с внешними библиотеками анимации, такими как GSAP, anime.js или Framer Motion (через Web Components). Пример с GSAP:

import { c, useEffect, useRef } from "atomico";
import { gsap } from "gsap";

function GsapFade() {
    const ref = useRef();

    useEffect(() => {
        gsap.from(ref.current, { opacity: 0, y: 30, duration: 0.5 });
    }, []);

    return <div ref={ref}>GSAP-анимация при монтировании</div>;
}

customElements.define("gsap-fade", c(GsapFade));

Преимущества интеграции:

  • Возможность создавать сложные таймлайны анимаций.
  • Управление повторениями, easing и синхронизацией с другими элементами.
  • Поддержка динамических компонентов и условного рендеринга.

Анимация с условным рендерингом

Иногда требуется запуск анимации только при появлении компонента в DOM в ответ на условие. В Atomico это реализуется через реактивное свойство и хук useEffect.

import { c, useState, useEffect, useRef } from "atomico";

function ConditionalFade() {
    const [show, setShow] = useState(false);
    const ref = useRef();

    useEffect(() => {
        if (show && ref.current) {
            ref.current.style.opacity = 0;
            ref.current.style.transition = "opacity 0.5s";
            requestAnimationFrame(() => {
                ref.current.style.opacity = 1;
            });
        }
    }, [show]);

    return (
        <div>
            <button onCl ick={() => setShow(!show)}>Показать/Скрыть</button>
            {show && <div ref={ref}>Появляющийся блок</div>}
        </div>
    );
}

customElements.define("conditional-fade", c(ConditionalFade));

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

  • Анимация срабатывает только при монтировании.
  • Состояние show управляет условным рендерингом.
  • Комбинация useState и useEffect позволяет плавно интегрировать анимацию в логику приложения.

Выводы по практическому применению

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

Эти приёмы позволяют создавать веб-компоненты с плавными и отзывчивыми анимациями без потери производительности и гибкости реактивного подхода.