![](https://habrastorage.org/webt/qg/8g/ix/qg8gixddhfc3syhabrxtxgw6-hq.png)
Vue позволяет разработчикам писать более гибкий и переиспользуемый код за счёт наличия дополнительных возможностей для организации компонентов. И одной из областей применения этих возможностей являются анимации. В текущей статье мы разберём использование Composition API для создания анимаций в Vue с помощью CSS и JS библиотеки GSAP (GreenSock Animation Platform).
Примечание пер.: статья содержит крупные GIF-анимации.
Для начала мы рассмотрим принцип построения анимаций с помощью CSS. Для этого мы посредством директивы
v-bind
привяжем CSS класс к элементу, а затем, используя функцию анимации по ключевым кадрам, создадим саму анимацию. Вот как всё это может выглядеть в компоненте Vue 3:![](https://habrastorage.org/webt/_8/ve/iy/_8veiy0jilycov3kqwjmzk3gwf0.png)
![](https://habrastorage.org/webt/uv/oo/pw/uvoopwe9coxvnvnyijwcisc2stc.gif)
Итоговая анимация в формате GIF
В этом примере у нас есть элемент
div
с классом fade
. Мы привязываем класс in
или out
, переключая значение animationStarted
событием клика. Затем начинается анимация по ключевым кадрам, которая демонстрирует появляющийся и затухающий текст с динамическим эффектом (ease).Вот ещё один пример анимирования элементов с использованием перехода (transition) и класса
v-bind
.![](https://habrastorage.org/webt/d1/hl/je/d1hljeg8u6dmbvdgpqhyxgv32fi.png)
![](https://habrastorage.org/webt/fd/oc/hf/fdochfoiculegvxcycumna3yheu.gif)
Результат в формате GIF
В этом примере у нас есть элемент
img
с классом fadeIn
. Мы привязываем класс active
, переключая значение animated
с помощью события клика. Затем мы связываем значение animated
в элементе style
со свойством opacity
. При этом animated
является логическим значением, то есть может быть равно 1 или 0.Теперь немного углубимся и используем дополнительные события.
![](https://habrastorage.org/webt/zr/nv/df/zrnvdflklbhepx7_t5ofwuoocqe.png)
![](https://habrastorage.org/webt/lg/bj/x5/lgbjx5oosftu17lmbmt2oqqnlm4.gif)
В этом примере у нас есть шаблон Vue с элементом
img
, содержащим слушателей событий mousemove
и mouseleave
. При наведении мыши на изображение вызывается функция getMousePos
, которая вычисляет положение курсора относительно центра изображения и обновляет несколько реактивных переменных. Затем эти переменные используются для трансформации изображения, например, его поворота относительно осей X и Y, и применения отбрасываемой тени с цветом, определяемым положением курсора. Когда же курсор изображение покидает, вызывается функция resetPos
, сбрасывающая реактивные переменные на начальные значения.А вот ещё один пример с использованием события
mousemove
:![](https://habrastorage.org/webt/el/zm/tr/elzmtrjmk8qddv5pgwmwjvrjpzk.png)
![](https://habrastorage.org/webt/sv/hh/og/svhhognvk8j8xg8ma1glnlfeeow.gif)
Тут мы создаём на изображении эффект прожектора, используя радиальный градиент. При этом положение светового пятна управляется движением мыши. Этот эффект можно включать и отключать кнопкой. В Vue эта возможность реализуется с помощью компонента
Teleport
, который позволяет перемещать прожектор в другую часть DOM без необходимости использовать сложное позиционирование. Положение прожектора сохраняется в реактивных переменных с помощью ref()
, а движение мыши отслеживается с помощью события @mousemove
. Для стилизации используется код CSS, в котором параметры opacity
и position
регулируются посредством переходов.Теперь мы создадим более продвинутую анимацию, используя библиотеку GSAP, которая позволяет реализовывать роскошные и привлекательные пользовательские интерфейсы с динамическими анимациями. GSAP предоставляет широкий спектр возможностей для анимирования HTML-элементов, а также отличается высоким быстродействием и может анимировать элементы плавно даже на слабых устройствах.
Для использования этой библиотеки с Vue нужно её установить через
npm install gsap
. Для этого примера мы анимируем заголовки hero-раздела и изображение.![](https://habrastorage.org/webt/xy/wu/sc/xywuscursj1pbsgnrk5nfuaovq4.png)
![](https://habrastorage.org/webt/vh/tz/_9/vhtz_9-7jvm1jn7j-iqmewc607s.gif)
Здесь мы использовали GSAP для создания анимаций в приложении Vue.js. Мы импортировали функции
gsap
и ref
, которые позволили нам создать реактивные данные и обращаться к элементам в DOM. Затем мы создали реф revealUp
, ссылающуюся на изображение, которое мы хотим анимировать. Функция animateImage
использует метод gsap.fromTo
для анимирования изображения путём изменения его свойств opacity
, clipPath
, autoAlpha
, scale
, delay
, duration
и ease
.Аналогичным образом функция
animateInfo
анимирует текстовые элементы, используя метод gsap.timeline
для создания временной линии отображения каждого из них с помощью класса revealUp
. При этом здесь также используется метод fromTo
со свойством stagger
для поочерёдного вывода анимируемых элементов.Stagger – это функционал библиотеки GSAP, который позволяет создавать последовательные анимации с временной задержкой между отображением каждого элемента. Это пригождается, когда мы хотим анимировать группу элементов в определённом порядке.
Наконец, мы используем хук
onMounted
для вызова функций animateInfo
и animateImage
в момент монтирования компонента, чтобы анимации выполнялись сразу после отрисовки этого компонента.Далее мы создадим в Vue.js кастомную директиву для использования GSAP.
![](https://habrastorage.org/webt/5a/er/h4/5aerh4r44efiqkwufxsc9fqrgdy.png)
![](https://habrastorage.org/webt/tl/k1/tq/tlk1tq9xaz1epqfjq5p9y80zlws.gif)
В этом примере мы создали собственную директиву
vGsap
, которая позволит привязывать анимации к HTML-элементам на основе определённых событий, таких как mouseenter
, click
и так далее.Сначала мы импортировали библиотеку GSAP, после чего определили три разных функции анимации для тестирования —
animateRevealDown
, animateRevealLeft
и animatePulseRingEffect
– каждую со своей временной линией, определяющей порядок анимирования элементов.Затем мы создали директиву
vGsap
, получающую два аргумента: анимируемый элемент и применяемую анимацию. Эта директива настраивает слушателя на прослушивание конкретного события и активирует анимацию при его возникновении. Если событием оказывается mouseenter
, мы также устанавливаем слушателя для mouseleave
и используем метод gasp.to
для анимирования элемента обратно в исходное состояние, когда курсор мыши его покидает.Наконец, мы использовали директиву
v-gasp
в шаблоне для анимирования элементов. Мы передали ей объект, устанавливающий событие для прослушивания, и анимацию для применения к каждому нужному элементу.В целом директива vGsap позволяет нам с лёгкостью создавать анимации и управлять ими, просто добавляя атрибуты в нужный HTML-элемент. Такое удобство делает её полезным инструментом фронтенд-разработки, позволяющим реализовывать в веб-приложениях динамические и интригующие эффекты.
Теперь мы сделаем шаг ещё дальше и познакомимся с использованием в приложениях Vue.js 3D-моделирования. В этом случае основанная на компонентах архитектура Vue предоставляет прекрасную основу для реализации трёхмерной графики, способствующей более погружающему и интригующему пользовательскому опыту. Здесь мы будем использовать библиотеку Trois.js, которая упростит интеграцию популярной библиотеки 3D-графики Three.js. Мы разберём создание и управление 3D-сценами, моделями и анимациями, а также научимся кастомизировать их под необходимые критерии.
С помощью Trois.js можно создавать сложные реактивные и интерактивные 3D-приложения, используя знакомые принципы Vue.js, такие как свойства, события и хуки жизненного цикла. Эта библиотека включает широкий спектр готовых компонентов, в том числе освещение, камеры, модели и эффекты пост-обработки, которые можно легко добавлять в приложение и настраивать желаемым образом.
Мы научимся создавать динамические и интерактивные эффекты для изображения. Проработав приведённый пример, вы хорошо уясните, как создавать эти эффекты с помощью Vue.js и Three.js. Вы также научитесь использовать библиотеку Trois.js для работы с Three.js в приложениях Vue.
![](https://habrastorage.org/webt/k2/oi/uy/k2oiuyvlrlc1zwrpxwxqekmhvcc.png)
![](https://habrastorage.org/webt/bw/wx/it/bwwxitjiur-q45hp5hguok9ezua.gif)
Результат применения готового компонента
Noisy Image Shader
в формате GIFВ этом примере шаблон начинается с компонента <Renderer>, создающего отрисовщик WebGL, который будет отрисовывать 3D-сцену. У этого отрисовщика есть ряд свойств, включая ширину и высоту, а также настройки для альфа-канала, контроля вращения камеры и теней. Внутри отрисовщика присутствует компонент <Camera>, настраивающий начальное положение камеры. За ним следует компонент <Scene>, представляющий 3D-сцену.
Основной акцент в этом примере делается на готовый компонент <NoisyImage>, который будет создавать шумную анимированную версию изображения. Здесь мы использовали для управления анимацией различные свойства, а именно
time-coef
, noise-coef
и z-coef
.:disp-coef
управляет эффектом смещения изображения;:noise-coef
управляет степенью применяемого к изображению шума;:time-coef
– коэффициент, определяющий фактор времени применяемой текстуры шума;:z-coef
– коэффициент, влияющий на смещение текстуры шума по оси z;
Мы также использовали события
@pointerOver
и @pointerLeave
для активации различных состояний анимации при взаимодействии пользователя с изображением.В процессе создания анимации с помощью библиотеки GSAP мы подстраивали значения определённых свойств. Это позволяет нам осуществлять плавный переход между различными состояниями анимации на основе пользовательского ввода.
Теперь мы научимся использовать
troisjs
для создания 3D-сцены с моделью, загружаемой из внешнего файла.![](https://habrastorage.org/webt/-8/e4/gg/-8e4ggw5y-rbbgj7ioka32nlkww.png)
![](https://habrastorage.org/webt/y7/0y/zs/y70yzs-0mgr7xaaxk9kojgyti98.gif)
Этот пример отличается лишь тем, что сцена включает компонент <AmbientLight>, который обеспечивает фоновое освещение и компонент <PointLight>, создающий точечный свет. Для обоих видов освещения установлено отбрасывание теней.
Наконец, сцена содержит компонент <GltfModel>, который загружает 3D-модель из указанного файла. После загрузки вызывается функция
onReady
. Она устанавливает AnimationMixer
, который будет анимировать модель и запускать анимацию, воспроизводя первый клип. При этом также устанавливаются часы для отслеживания времени анимации.В завершении для отрисовки каждого кадра вызывается функция
updateMixer
, которая обновляет AnimationMixer
, вызывая его метод update
с указанием количества времени, прошедшего с момента отрисовки последнего кадра.При отрисовке каждого кадра вызывается
mixer.value.update
, которая получает количество времени, прошедшего после рендеринга предыдущего кадра. Вычисляется это время функцией clock.value.getDelta()
. Вызов этого метода обновляет состояние mixer
на основе прошедшего времени и требуется для плавного воспроизведения анимаций на сцене.Вуаля! Мы успешно встроили 3D-модель на наш сайт.
Благодарю вас за уделённое время. Надеюсь, что статья оказалась для вас полезной и вдохновила на применение некоторых из описанных в ней техник и инструментов в собственных проектах. Постепенно раскрывая весь потенциал анимаций Vue, вы начнёте создавать более привлекательные и динамические интерфейсы, улучшающие пользовательский опыт и заметно выделяющие ваши приложения. Высокая гибкость Composition API и обширный функционал GSAP делают ваши возможности практически безграничными.
Удачного анимирования!
Telegram-канал с розыгрышами призов, новостями IT и постами о ретроиграх 🕹️
![](https://habrastorage.org/webt/_p/_h/lv/_p_hlvd2tv0cv9tny8tdytzfhje.png)