Анимация списков

Atomico — библиотека для создания веб-компонентов с реактивной архитектурой, которая предоставляет удобные инструменты для анимации элементов, в том числе списков. Управление состоянием и реактивность компонентов позволяет реализовать плавные переходы при добавлении, удалении и изменении элементов.

Реактивные списки

Основной принцип работы с анимацией списков в Atomico — реактивное отслеживание изменений массива данных. Состояние списка обычно хранится с помощью функции useState, а при его изменении компоненты перерендериваются, что позволяет интегрировать анимацию добавления или удаления элементов.

import { c, useState } from "atomico";

function List() {
    const [items, setItems] = useState(["Элемент 1", "Элемент 2"]);

    return (
        <host>
            <ul>
                {items.map(item => (
                    <li>{item}</li>
                ))}
            </ul>
            <button onCl ick={() => setItems([...items, `Элемент ${items.length + 1}`])}>
                Добавить элемент
            </button>
        </host>
    );
}

customElements.define("animated-list", c(List));

Анимация при добавлении и удалении

Для анимации используется сочетание CSS-переходов и реактивных хуков Atomico. Для плавного появления нового элемента применяют переходы по свойствам opacity и transform.

li {
    transition: opacity 0.3s ease, transform 0.3s ease;
    opacity: 0;
    transform: translateY(-10px);
}

li.entered {
    opacity: 1;
    transform: translateY(0);
}

JavaScript-часть отвечает за добавление класса .entered после монтирования элемента:

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

function List() {
    const [items, setItems] = useState([]);
    const [enteredItems, setEnteredItems] = useState([]);

    useEffect(() => {
        setEnteredItems(items.map((item, index) => ({ item, id: index })));
    }, [items]);

    const addItem = () => setItems([...items, `Элемент ${items.length + 1}`]);

    return (
        <host>
            <ul>
                {enteredItems.map(({ item, id }) => (
                    <li key={id} class="entered">{item}</li>
                ))}
            </ul>
            <button onCl ick={addItem}>Добавить элемент</button>
        </host>
    );
}

customElements.define("animated-list", c(List));

Плавное удаление

Удаление элемента требует двух этапов: сначала анимация исчезновения, затем удаление из массива. Для этого используют временные состояния и setTimeout с длительностью CSS-перехода.

function removeItem(index) {
    const updated = [...enteredItems];
    updated[index].removing = true;
    setEnteredItems(updated);

    setTimeout(() => {
        setItems(items.filter((_, i) => i !== index));
    }, 300); // Длительность анимации
}

CSS для удаления:

li.removing {
    opacity: 0;
    transform: translateY(-10px);
}

Реактивные ключи и производительность

Atomico использует реактивные ключи (key) для отслеживания изменений списка. Это предотвращает перерендер всех элементов при добавлении или удалении одного и позволяет оптимизировать анимацию. В примерах выше key={id} гарантирует правильное сопоставление элементов DOM с данными массива.

Сложные анимации

Для более сложных эффектов можно использовать функцию useAnimationFrame, чтобы управлять анимацией через JavaScript, создавая последовательное появление элементов или эффекты “staggered” (поочередное появление).

import { useAnimationFrame } from "atomico";

useAnimationFrame((time) => {
    // Реализовать последовательное появление элементов
});

Комбинируя useAnimationFrame с состояниями элементов, можно создавать эффекты масштабирования, вращения, сдвига и затухания, которые сложно реализовать чисто через CSS-переходы.

Итоговый подход

  1. Использовать useState для управления массивом данных.
  2. Применять классы для анимации входа (entered) и выхода (removing).
  3. Управлять удалением через таймер, соответствующий длительности CSS-перехода.
  4. Назначать уникальные ключи для каждого элемента списка.
  5. Для сложных эффектов применять useAnimationFrame или библиотечные анимации.

Такой подход позволяет создавать интерактивные списки с плавными визуальными эффектами, минимизируя количество лишних перерендеров и сохраняя реактивность компонентов Atomico.