Vue

Анимации: <Transition> и <TransitionGroup>

Модалка появляется рывком, тост о новом сообщении мигает на месте, а при удалении строки из списка соседи скачком сдвигаются вверх. Дизайнер просит сделать переходы плавными, и первый порыв это навесить setTimeout и руками переключать классы. Но Vue уже знает, когда элемент входит в DOM и когда выходит, и умеет ждать завершения CSS-анимации перед удалением узла. Компоненты <Transition> и <TransitionGroup> дают эту синхронизацию: появление, исчезновение и даже плавную перестановку элементов списка при сортировке.

  • Модальные окна и выезжающие панели: <Transition> анимирует появление и скрытие при смене условия v-if
  • Тосты и уведомления: список сообщений на <TransitionGroup> с анимацией добавления и удаления
  • Канбан-доски и сортируемые списки: move-анимация плавно сдвигает карточки при перестановке
  • Переключение вкладок и шагов формы: именованные переходы дают каждому экрану свою анимацию
  • Интеграция GSAP и motion: JavaScript-хуки <Transition> запускают сторонний движок анимации в нужный момент

Предварительные знания

  • Условный рендеринг через v-if и v-show и рендеринг списков через v-for
  • Базовое знание CSS-переходов и keyframe-анимаций
  • Понимание, что элемент появляется и исчезает из DOM при смене условия

<Transition> и шесть CSS-классов

<Transition> это встроенный компонент-обёртка для одного элемента или компонента, который появляется или исчезает. Триггером служит v-if, v-show или смена динамического компонента. В момент входа и выхода Vue навешивает на элемент серию CSS-классов, по которым описывается анимация. Сам Vue ничего не анимирует: он лишь добавляет и снимает классы в правильные моменты и ждёт завершения CSS-перехода, прежде чем удалить узел из DOM.

КлассКогда применяетсяНазначение
v-enter-fromОдин кадр перед входомСтартовое состояние: например, opacity 0
v-enter-activeВсю фазу входаОписывает transition: длительность и easing
v-enter-toПосле начала входа до концаКонечное состояние входа: opacity 1
v-leave-fromОдин кадр перед выходомСтартовое состояние выхода: opacity 1
v-leave-activeВсю фазу выходаОписывает transition выхода
v-leave-toПосле начала выхода до удаленияКонечное состояние: opacity 0

Класс с суффиксом active это единственное место, где описывается само свойство transition с длительностью и функцией плавности. Классы from и to задают только начальное и конечное состояние. Vue читает длительность из вычисленного transition и именно по ней понимает, когда анимация закончилась и узел можно удалить.

В каком из классов перехода описывается само свойство transition с длительностью и easing?

Именованные переходы

Префикс v у классов это значение по умолчанию. Когда на одной странице нужно несколько разных анимаций (модалка выезжает снизу, тост проявляется, вкладка сдвигается вбок), их различают через атрибут name. Имя заменяет префикс v на заданное, и классы становятся, например, slide-enter-from и slide-enter-active. Так у каждого перехода своя независимая группа классов.

Переход также различает три режима появления и исчезновения относительно друг друга. По умолчанию входящий и выходящий элементы анимируются одновременно, из-за чего при переключении они на миг накладываются. Атрибут mode со значением out-in заставляет сначала доиграть выход старого элемента, а потом запустить вход нового. Это типичный выбор для переключения вкладок или экранов, где наложение выглядит грязно.

При переключении динамического компонента важен атрибут key. Без него Vue может переиспользовать тот же DOM-узел для нового компонента, и переход не сработает, ведь элемент формально не покидал DOM. Уникальный key на каждом варианте заставляет Vue считать это полноценной заменой и проиграть анимацию.

На странице нужно два разных перехода: один для модалки, другой для бокового меню. Как их разделить?

<TransitionGroup> и JavaScript-хуки

<Transition> работает с одним элементом. Для списка, который меняется (элементы добавляются, удаляются, переставляются), нужен <TransitionGroup>. Он анимирует вход и выход каждого элемента так же, как <Transition>, и дополнительно даёт класс v-move для плавного сдвига соседей. Когда из списка удаляют строку, остальные не прыгают вверх скачком, а плавно сдвигаются. Каждый элемент группы обязан иметь уникальный key, иначе Vue не сможет отследить, какой элемент куда переехал.

Класс v-move (здесь list-move) это то, что отличает <TransitionGroup> от обычной анимации. Vue применяет технику FLIP: запоминает позицию каждого элемента до и после изменения списка и анимирует разницу через transform. Поэтому при сортировке или удалении соседние элементы плавно переезжают на новые места. Без описанного move-класса перестановка происходит мгновенным скачком.

Когда CSS не хватает (нужен физический spring, сложная траектория, интеграция со сторонним движком), переход принимает JavaScript-хуки. Это события before-enter, enter, after-enter и зеркальные для выхода. В хуке enter второй аргумент это callback done: пока его не вызвать, Vue считает анимацию незавершённой и не удаляет элемент. Это и есть мост к GSAP, motion и любой другой библиотеке.

При использовании JS-хуков с собственным движком ставят атрибут :css="false". Он говорит Vue не искать CSS-классы и не ждать CSS-переход, а полагаться только на вызов done. Без этого Vue может удалить элемент по таймауту CSS раньше, чем JS-анимация доиграет.

При удалении элемента из списка соседние элементы должны плавно сдвигаться, а не прыгать. Что это обеспечивает в <TransitionGroup>?

Связь с другими темами

Урок опирается на синтаксис шаблонов и смыкается с производительностью списков:

  • Синтаксис шаблонов — Переход оборачивает v-if, v-show и v-for, поэтому условия и списки это его основа
  • Производительность Vue — Анимация большого списка упирается в стоимость DOM-операций при перестановке

Итог

  • <Transition> анимирует появление и исчезновение одного элемента при смене v-if, v-show или динамического компонента, навешивая CSS-классы на фазы входа и выхода
  • Шесть классов перехода: v-enter-from, v-enter-active, v-enter-to и три зеркальных для выхода, где active содержит свойство transition
  • Атрибут name меняет префикс классов с v на заданное имя, что позволяет держать несколько разных переходов на странице
  • <TransitionGroup> анимирует список элементов с key и добавляет класс v-move для плавного сдвига соседей при добавлении, удалении и сортировке
  • JavaScript-хуки перехода (before-enter, enter, leave и другие) дают точку интеграции со сторонними движками анимации вроде GSAP
  • Vue ждёт завершения CSS-перехода или вызова done в JS-хуке прежде чем удалить элемент из DOM

Связанные уроки

  • vue-38-performance — Анимация большого списка через TransitionGroup упирается в те же ограничения DOM, что и производительность
  • vue-04-template-syntax — Переходы оборачивают условный рендеринг и списки, которые задаются директивами шаблона
Анимации: <Transition> и <TransitionGroup>

0

1

Войти