Vue.js предоставляет мощные встроенные возможности для работы с
анимациями через директивы v-bind:class,
v-show, v-if и компонент
<transition>. Однако для создания сложных и
кастомизированных визуальных эффектов часто используется интеграция с
внешними библиотеками анимаций, такими как GSAP (GreenSock
Animation Platform), Anime.js,
Velocity.js и CSS-фреймворки типа
Animate.css. Интеграция позволяет сочетать реактивность
Vue с гибкостью внешних инструментов.
<transition> с внешними библиотекамиКомпонент <transition> является ключевым
инструментом для анимации при добавлении и удалении элементов. При
интеграции с библиотеками анимаций можно использовать хуки жизненного
цикла:
before-enterenterafter-enterenter-cancelledbefore-leaveleaveafter-leaveleave-cancelledПример использования GSAP для анимации появления элемента:
<template>
<transition
@enter="enterAnimation"
@leave="leaveAnimation"
>
<div v-if="visible" class="box"></div>
</transition>
</template>
<script>
import { gsap } from "gsap";
export default {
data() {
return { visible: true };
},
methods: {
enterAnimation(el, done) {
gsap.fromTo(el, { opacity: 0, y: -50 }, { opacity: 1, y: 0, duration: 0.5, onComplete: done });
},
leaveAnimation(el, done) {
gsap.to(el, { opacity: 0, y: 50, duration: 0.5, onComplete: done });
}
}
}
</script>
<style>
.box {
width: 100px;
height: 100px;
background-color: #42b983;
}
</style>
Ключевой момент: функция done должна
вызываться после завершения анимации, иначе Vue не завершит процесс
изменения DOM.
<transition-group>Для анимации динамических списков используется компонент
<transition-group>. Он поддерживает как встроенные
CSS-анимации, так и библиотеки JS-анимаций.
Пример с Anime.js:
<template>
<transition-group name="list" tag="ul" @before-enter="beforeEnter" @enter="enter">
<li v-for="item in items" :key="item.id">{{ item.text }}</li>
</transition-group>
</template>
<script>
import anime from 'animejs/lib/anime.es.js';
export default {
data() {
return { items: [{ id: 1, text: 'Первый' }, { id: 2, text: 'Второй' }] };
},
methods: {
beforeEnter(el) {
el.style.opacity = 0;
el.style.transform = 'translateY(-20px)';
},
enter(el, done) {
anime({
targets: el,
opacity: 1,
translateY: 0,
duration: 500,
easing: 'easeOutExpo',
complete: done
});
}
}
}
</script>
Особенность: <transition-group>
требует уникального key для каждого элемента, иначе
анимация работать не будет.
Использование готовых CSS-библиотек, таких как Animate.css, позволяет ускорить процесс без написания JS-кода. Для этого достаточно назначить классы анимации через директивы Vue:
<template>
<transition name="animate__fadeIn">
<div v-if="show" class="box"></div>
</transition>
</template>
<script>
export default {
data() {
return { show: true };
}
}
</script>
<style>
@import "https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css";
.box {
width: 100px;
height: 100px;
background-color: #42b983;
}
</style>
Принцип работы: Vue автоматически добавляет и
убирает классы *-enter-active, *-leave-active,
что позволяет CSS-анимациям запускаться синхронно с изменением DOM.
Для повторного использования анимаций удобно создавать кастомные директивы Vue. Например, директива для GSAP:
// directives/gsap.js
import { gsap } from "gsap";
export default {
mounted(el, binding) {
gsap.from(el, { opacity: 0, y: binding.value?.y || 50, duration: binding.value?.duration || 0.5 });
}
}
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import gsapDirective from './directives/gsap';
const app = createApp(App);
app.directive('gsap', gsapDirective);
app.mount('#app');
Использование:
<div v-gsap="{ y: 30, duration: 1 }">Анимированный блок</div>
Преимущество: директива инкапсулирует анимацию и позволяет применять её к любым элементам без повторного кода.
При работе с большими списками или сложными анимациями следует учитывать следующие моменты:
requestAnimationFrame или встроенные
методы библиотек, чтобы избежать блокировки рендеринга.transform, opacity) вместо width
или height.Vue позволяет комбинировать библиотеки для различных задач:
Комбинация библиотек реализуется через хуки
<transition> и <transition-group>
либо кастомные директивы. Важно следить за конфликтами классов и
таймингов, чтобы не нарушать реактивность Vue.
Vue позволяет связывать анимации с реактивными данными, что открывает возможности создания динамических эффектов, зависящих от состояния приложения:
<template>
<div :class="animationClass">Контент</div>
</template>
<script>
export default {
data() {
return { isActive: false };
},
computed: {
animationClass() {
return this.isActive ? 'fade-in' : 'fade-out';
}
}
}
</script>
<style>
.fade-in {
animation: fadeIn 0.5s forwards;
}
.fade-out {
animation: fadeOut 0.5s forwards;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }
</style>
Эта методика позволяет синхронизировать визуальные эффекты с логикой приложения, что особенно полезно для динамических интерфейсов, модальных окон и уведомлений.