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

Vue.js предоставляет мощные средства для создания плавных анимаций элементов DOM. Для работы с динамическими списками используется компонент <transition-group>, который позволяет анимировать добавление, удаление и перестановку элементов внутри коллекций. Основная особенность <transition-group> заключается в том, что он не оборачивает элементы одним контейнером, а оставляет их на месте в DOM, сохраняя структуру списка.


Основы использования <transition-group>

Компонент <transition-group> работает аналогично обычному <transition>, но применяется к нескольким элементам одновременно. Ключевые свойства:

  • name — базовое имя CSS-класса для анимации.
  • tag — HTML-тег, который будет использоваться в качестве контейнера для группы элементов.
  • appear — позволяет анимацию при первичном отображении списка.
  • type — задаёт тип анимации (transition или animation).

Пример базовой структуры:

<template>
  <transition-group name="fade" tag="ul">
    <li v-for="item in items" :key="item.id">
      {{ item.text }}
    </li>
  </transition-group>
</template>

<script>
export default {
  data() {
    return {
      items: [
        { id: 1, text: 'Элемент 1' },
        { id: 2, text: 'Элемент 2' },
        { id: 3, text: 'Элемент 3' }
      ]
    };
  }
};
</script>

<style>
.fade-enter-active, .fade-leave-active {
  transition: opacity 0.5s;
}
.fade-enter-from, .fade-leave-to {
  opacity: 0;
}
</style>

В этом примере при добавлении или удалении элементов списка будет применяться плавное появление и исчезновение через прозрачность.


Работа с ключами элементов

Правильная работа <transition-group> зависит от уникальных ключей (key) для каждого элемента. Vue использует ключи для отслеживания изменений в списке и определения, какие элементы добавляются, удаляются или перемещаются. Отсутствие уникальных ключей приведёт к некорректной анимации или её отсутствию.

<li v-for="item in items" :key="item.id">{{ item.text }}</li>

item.id должен быть уникальным в пределах списка. Для массивов без идентификаторов можно использовать индекс, но это приведёт к повторной отрисовке элементов при перестановках, а не к анимации движения.


Анимация перемещения элементов

Помимо появления и исчезновения, <transition-group> поддерживает анимацию перестановки элементов с помощью класса move. Для этого требуется включить transition с использованием CSS свойств transform или top/left:

<style>
.list-move {
  transition: transform 0.5s;
}
</style>

Vue автоматически добавляет класс -move элементам, которые изменили своё положение, обеспечивая плавное смещение вместо резкого прыжка. Для правильной работы анимации необходимо, чтобы элементы имели фиксированную высоту или использовалась flex-структура.


Использование анимаций с библиотеками

Для сложных анимаций можно использовать библиотеки типа Animate.css или GSAP, комбинируя их с событиями <transition-group>:

<transition-group
  name="slide"
  tag="ul"
  @before-enter="beforeEnter"
  @enter="enter"
  @leave="leave"
>
  <li v-for="item in items" :key="item.id">{{ item.text }}</li>
</transition-group>
methods: {
  beforeEnter(el) {
    el.style.transform = 'translateX(-100%)';
  },
  enter(el, done) {
    gsap.to(el, { x: 0, duration: 0.5, onComplete: done });
  },
  leave(el, done) {
    gsap.to(el, { x: 100, opacity: 0, duration: 0.5, onComplete: done });
  }
}

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


Стилизация анимаций через CSS

Компонент <transition-group> использует следующие CSS-классы для управления анимацией:

  • v-enter-from / v-enter-active / v-enter-to — появление элемента.
  • v-leave-from / v-leave-active / v-leave-to — исчезновение элемента.
  • v-move — перемещение элемента внутри группы.

Пример:

.list-enter-from {
  opacity: 0;
  transform: translateY(-20px);
}
.list-enter-active {
  transition: all 0.3s ease;
}
.list-leave-to {
  opacity: 0;
  transform: translateY(20px);
}
.list-move {
  transition: transform 0.3s;
}

Эти классы автоматически применяются Vue при изменении списка, обеспечивая полный контроль над визуальными эффектами.


Важные нюансы

  1. Не использовать анимацию без ключей. Ключи обязательны для отслеживания изменений.
  2. Контейнер <transition-group> всегда нужен. Он управляет анимацией, но может быть любым HTML-элементом через tag.
  3. Совместимость с flex и grid. Для корректного перемещения элементов желательно использовать flex-контейнеры или фиксированную высоту элементов.
  4. Комбинирование с JS-анимациями. Можно использовать коллбеки before-enter, enter, leave, что позволяет интегрировать GSAP или другие библиотеки для более гибкой анимации.

Анимация списков через <transition-group> является мощным инструментом Vue.js, позволяющим создавать плавные, интерактивные интерфейсы без сложных манипуляций с DOM, сохраняя декларативный подход и высокую производительность.