Анимация RouterView

В Vue Router компонент <router-view> служит контейнером для отображения компонентов, соответствующих текущему маршруту. Для создания плавных переходов между страницами используется встроенная поддержка Vue Transition и TransitionGroup. Анимация в RouterView реализуется через комбинацию transition и динамических ключей, позволяющих Vue отслеживать смену компонентов.

Базовая анимация при смене маршрута

Для применения простых анимаций достаточно обернуть <router-view> в компонент <transition>:

<template>
  <transition name="fade" mode="out-in">
    <router-view :key="$route.fullPath"></router-view>
  </transition>
</template>

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

Пояснения:

  • name="fade" — базовое имя для классов анимации.
  • mode="out-in" — определяет порядок анимации: текущий компонент сначала уходит, затем появляется новый.
  • :key="$route.fullPath" — динамический ключ, который обеспечивает корректную перерисовку при изменении маршрута, предотвращая повторное использование компонента.

Выбор режима анимации

Vue поддерживает два основных режима:

  1. out-in — старый компонент полностью уходит, затем появляется новый. Используется для анимации «замещения» содержимого.
  2. in-out — новый компонент появляется поверх старого, который затем скрывается. Подходит для наложений и плавных переходов с эффектом overlay.
<transition name="slide" mode="in-out">
  <router-view :key="$route.path"></router-view>
</transition>

Классы для анимации сдвига:

.slide-enter-active, .slide-leave-active {
  transition: transform 0.3s ease, opacity 0.3s ease;
}
.slide-enter-from {
  transform: translateX(100%);
  opacity: 0;
}
.slide-leave-to {
  transform: translateX(-100%);
  opacity: 0;
}

Анимация при вложенных маршрутах

При работе с вложенными <router-view> необходимо учитывать несколько уровней переходов. Каждый <router-view> может иметь собственный <transition>:

<template>
  <div>
    <transition name="fade" mode="out-in">
      <router-view :key="$route.fullPath"></router-view>
    </transition>
    <transition name="slide" mode="out-in">
      <router-view name="nested" :key="$route.fullPath"></router-view>
    </transition>
  </div>
</template>

Использование разных name позволяет создавать независимые анимации для главного и вложенного маршрута.

Переходы между маршрутами с динамическими параметрами

Для маршрутов с параметрами важно использовать ключ, который учитывает изменение параметров:

<router-view :key="$route.params.id"></router-view>

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

Сложные переходы с <transition> и <transition-group>

Если требуется анимировать списки или несколько компонентов одновременно, применяется <transition-group>:

<transition-group name="list" tag="div">
  <router-view v-for="item in items" :key="item.id"></router-view>
</transition-group>

Классы анимации для групп:

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

Анимация при навигации программным способом

При использовании router.push или router.replace можно отслеживать направление перехода, чтобы динамически менять анимацию:

<template>
  <transition :name="transitionName">
    <router-view :key="$route.fullPath"></router-view>
  </transition>
</template>

<script>
export default {
  data() {
    return {
      transitionName: 'fade'
    }
  },
  watch: {
    '$route'(to, from) {
      const toIndex = parseInt(to.meta.index || 0);
      const fromIndex = parseInt(from.meta.index || 0);
      this.transitionName = toIndex > fromIndex ? 'slide-left' : 'slide-right';
    }
  }
}
</script>

В этом примере используется meta.index маршрута для определения направления анимации, что позволяет создавать эффект навигации «вперед» и «назад», аналогично мобильным приложениям.

Работа с библиотеками сторонних анимаций

Vue Router совместим с CSS-библиотеками анимации (Animate.css, GSAP). Применение GSAP позволяет создавать сложные последовательности переходов:

import { gsap } from "gsap";

export default {
  methods: {
    enterAnimation(el, done) {
      gsap.fromTo(el, { opacity: 0, x: 100 }, { opacity: 1, x: 0, duration: 0.5, onComplete: done });
    },
    leaveAnimation(el, done) {
      gsap.to(el, { opacity: 0, x: -100, duration: 0.5, onComplete: done });
    }
  }
}
<transition
  v-on:enter="enterAnimation"
  v-on:leave="leaveAnimation"
  mode="out-in"
>
  <router-view :key="$route.fullPath"></router-view>
</transition>

Использование JavaScript-хуков <transition> дает полный контроль над временной шкалой, синхронизацией и сложными эффектами.

Рекомендации по оптимизации анимации

  • Всегда использовать динамический ключ (key) для <router-view> при смене маршрутов.
  • Предпочтительно задавать mode="out-in" для корректного скрытия старого компонента перед показом нового.
  • Для вложенных маршрутов применяются независимые <transition> с разными именами.
  • Сложные анимации лучше реализовывать через JavaScript-хуки или сторонние библиотеки для гибкого управления временем и эффектами.
  • Использование CSS-переменных позволяет создавать масштабируемые темы анимации без повторного дублирования кода.