Skip to content

Перехід

Vue пропонує два вбудовані компоненти, які можуть допомогти працювати з переходами та анімацією в залежності від зміни стану:

  • <Transition> для застосування анімації, коли елемент або компонент входить і виходить з DOM. Про це йдеться на цій сторінці.

  • <TransitionGroup> для застосування анімації, коли елемент або компонент вставляється в список v-for, видаляється з нього або переміщується всередині нього. Це описано в наступному розділі.

Окрім цих двох компонентів, ми також можемо застосовувати анімацію у Vue за допомогою інших методів, таких як перемикання класів CSS або керована станом анімація за допомогою прив’язки стилів. Ці додаткові методи описано в розділі техніки анімації.

Компонент <Transition>

<Transition> є вбудованим компонентом: це означає, що він доступний у будь-якому шаблоні компонента без необхідності його реєстрації. Його можна використовувати для застосування анімацій входу та виходу до елементів або компонентів, переданих йому через слот за промовчанням. Вхід або вихід може бути ініційований одним із таких способів:

  • Умовний рендерінг через v-if
  • Умовне відображення через v-show
  • Перемикання динамічних компонентів через спеціальний елемент <component>
  • Зміна спеціального атрибута key

Ось приклад найпростішого використання:

template
<button @click="show = !show">Перемкнути зникнення</button>
<Transition>
  <p v-if="show">Привіт</p>
</Transition>
css
/* ми пояснимо, що ці класи роблять далі! */
.v-enter-active,
.v-leave-active {
  transition: opacity 0.5s ease;
}

.v-enter-from,
.v-leave-to {
  opacity: 0;
}

Привіт

TIP

<Transition> підтримує лише один елемент або компонент як вміст свого слота. Якщо вміст є компонентом, компонент також повинен мати лише один кореневий елемент.

Коли елемент у компоненті <Transition> вставляється або видаляється, відбувається наступне:

  1. Vue автоматично перевіряє, чи застосовано цільовому елементу CSS переходи або анімацію. Якщо це так, кілька класів переходу CSS буде додано/видалено у відповідний час.

  2. Якщо є слухачі для хуків JavaScript, ці хуки викликатимуться у відповідний час.

  3. Якщо переходів/анімацій CSS не виявлено та не вказано хуки JavaScript, операції DOM для вставки та/або видалення виконуватимуться в наступному кадрі анімації браузера.

Переходи на основі CSS

Перехідні класи

Існує шість класів, які застосовуються для переходів входу/виходу.

Діаграма переходу

  1. v-enter-from: Початковий стан для входу. Додається перед вставленням елемента, видаляється через один кадр після вставлення елемента.

  2. v-enter-active: активний стан для входу. Застосовується протягом всієї фази введення. Додається перед вставленням елемента, видаляється після завершення переходу/анімації. Цей клас можна використовувати для визначення тривалості, затримки та кривої послаблення для початкового переходу.

  3. v-enter-to: Кінцевий стан для входу. Додається один кадр після вставки елемента (одночасно видаляється v-enter-from), видаляється після завершення переходу/анімації.

  4. v-leave-from: Початковий стан для виходу. Додається негайно, коли запускається вихідний перехід, видаляється після одного кадру.

  5. v-leave-active: Активний стан для виходу. Застосовується протягом усього періоду виходу. Додається негайно, коли запускається вихідний перехід. Видаляється, коли перехід/анімація завершується. Цей клас можна використовувати для визначення тривалості, затримки та кривої послаблення для вихідного переходу.

  6. v-leave-to: Кінцевий стан для виходу. Додається з наступним кадром після запуску вихідного переходу (одночасно видаляється v-leave-from), видаляється після завершення переходу/анімації.

v-enter-active та v-leave-active дають нам можливість вказати різні криві послаблення для переходів входу/виходу, приклади яких ми побачимо в наступних розділах.

Іменовані переходи

Перехід можна назвати за допомогою реквізиту name:

template
<Transition name="fade">
  ...
</Transition>

Для іменованого переходу класи переходів будуть мати префікс свого імені замість v. Наприклад, застосований клас для вищезгаданого переходу буде fade-enter-active замість v-enter-active. CSS для переходу fade має виглядати так:

css
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

Переходи CSS

<Transition> найчастіше використовується в поєднанні з власними переходами CSS, як показано в базовому прикладі вище. Властивість CSS transition — це скорочення, яке дозволяє нам указати кілька аспектів переходу, включаючи властивості, які мають бути анімовані, тривалість переходу та криві послаблення.

Ось більш розширений приклад переходу між кількома властивостями з різною тривалістю та кривими послаблення для входу та виходу:

template
<Transition name="slide-fade">
  <p v-if="show">Привіт</p>
</Transition>
css
/*
  Анімації входу та виходу можуть по-різному використовувати
  функції тривалості та часу.
*/
.slide-fade-enter-active {
  transition: all 0.3s ease-out;
}

.slide-fade-leave-active {
  transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}

.slide-fade-enter-from,
.slide-fade-leave-to {
  transform: translateX(20px);
  opacity: 0;
}

Привіт

CSS анімації

Рідні анімації CSS застосовуються так само, як переходи CSS, з тією різницею, що *-enter-from видаляється не відразу після вставки елемента, а після події animationend.

Для більшості анімацій CSS ми можемо просто оголосити їх у класах *-enter-active і *-leave-active. Ось приклад:

template
<Transition name="bounce">
  <p v-if="show" style="text-align: center;">
    Привіт ось якийсь стрибучий текст!
  </p>
</Transition>
css
.bounce-enter-active {
  animation: bounce-in 0.5s;
}
.bounce-leave-active {
  animation: bounce-in 0.5s reverse;
}
@keyframes bounce-in {
  0% {
    transform: scale(0);
  }
  50% {
    transform: scale(1.25);
  }
  100% {
    transform: scale(1);
  }
}

Привіт, ось якийсь стрибучий текст!

Користувацькі класи переходу

Ви також можете вказати користувацькі класи переходів, передавши наступні реквізити до <Transition>:

  • enter-from-class
  • enter-active-class
  • enter-to-class
  • leave-from-class
  • leave-active-class
  • leave-to-class

Вони замінять звичайні назви класів. Це особливо корисно, коли ви хочете поєднати систему переходів Vue з існуючою бібліотекою анімації CSS, такою як Animate.css:

template
<!-- припустимо, що Animate.css включено на сторінку -->
<Transition
  name="custom-classes"
  enter-active-class="animate__animated animate__tada"
  leave-active-class="animate__animated animate__bounceOutRight"
>
  <p v-if="show">Привіт</p>
</Transition>

Використання переходів і анімації разом

Vue потрібно приєднати слухачів подій, щоб знати, коли перехід закінчився. Це може бути transitionend або animationend, залежно від типу застосованих правил CSS. Якщо ви використовуєте лише один або інший, Vue може автоматично визначити правильний тип.

Однак, у деяких випадках ви можете мати обидва на одному елементі, наприклад мати анімацію CSS, ініційовану Vue, разом із ефектом переходу CSS при наведенні. У цих випадках вам доведеться явно оголосити тип, про який Vue має піклуватися, передавши реквізит type зі значенням animation або transition:

template
<Transition type="animation">...</Transition>

Вкладені переходи та явні тривалості переходів

Хоча класи переходу застосовуються лише до прямого дочірнього елемента в <Transition>, ми можемо використовувати переходи у вкладених елементах за допомогою вкладених селекторів CSS:

template
<Transition name="nested">
  <div v-if="show" class="outer">
    <div class="inner">
      Привіт
    </div>
  </div>
</Transition>
css
/* правила, спрямовані на вкладені елементи */
.nested-enter-active .inner,
.nested-leave-active .inner {
  transition: all 0.3s ease-in-out;
}

.nested-enter-from .inner,
.nested-leave-to .inner {
  transform: translateX(30px);
  opacity: 0;
}

/* ... інший необхідний CSS пропущено */

Ми навіть можемо додати затримку переходу до вкладеного елемента під час входу, що створює послідовність анімації входу в шаховому порядку:

css
/* затримка введення вкладеного елемента для шахового ефекту */
.nested-enter-active .inner {
  transition-delay: 0.25s;
}

Однак це створює невелику проблему. За промовчанням компонент <Transition> намагається автоматично визначити, коли перехід завершився, прослуховуючи першу transitionend або animationend подію в кореневому елементі переходу. З вкладеним переходом бажана поведінка повинна чекати, поки завершаться переходи всіх внутрішніх елементів.

У таких випадках ви можете вказати тривалість переходу (у мілісекундах) за допомогою властивості duration компонента <transition>. Загальна тривалість має відповідати затримці плюс тривалість переходу внутрішнього елемента:

template
<Transition :duration="550">...</Transition>
Привіт

Спробуйте в пісочниці

Якщо необхідно, ви також можете вказати окремі значення для тривалості входу та виходу за допомогою об’єкта:

template
<Transition :duration="{ enter: 500, leave: 800 }">...</Transition>

Зауваження щодо продуктивності

Ви можете помітити, що показані вище анімації здебільшого використовують такі властивості, як transform і opacity. Ці властивості ефективні для анімації, оскільки:

  1. Вони не впливають на макет документа під час анімації, тому не запускають дорогий розрахунок макета CSS для кожного кадру анімації.

  2. Більшість сучасних браузерів можуть використовувати апаратне прискорення графічного процесора під час анімації transform.

Для порівняння, такі властивості, як height або margin, перебудовують макет CSS, тому їхня анімація набагато дорожча, і їх слід використовувати з обережністю. Ми можемо переглянути такі ресурси, як тригери CSS, щоб побачити, які властивості перебудовують макет, якщо ми їх анімуємо.

JavaScript хуки

Ви можете підключитися до процесу переходу за допомогою JavaScript, прослухавуючи події в компоненті <Transition>:

html
<Transition
  @before-enter="onBeforeEnter"
  @enter="onEnter"
  @after-enter="onAfterEnter"
  @enter-cancelled="onEnterCancelled"
  @before-leave="onBeforeLeave"
  @leave="onLeave"
  @after-leave="onAfterLeave"
  @leave-cancelled="onLeaveCancelled"
>
  <!-- ... -->
</Transition>
js
// викликається перед тим, як елемент буде вставлено в DOM.
// використовуйте це, щоб встановити стан "enter-from" елемента.
function onBeforeEnter(el) {}

// викликається з наступним кадром після вставки елемента.
// використовуйте це, щоб почати анімацію виходу.
function onEnter(el, done) {
  // викликає зворотний виклик done, щоб вказати кінець переходу.
  // необов'язковий, якщо використовується в поєднанні з CSS.
  done()
}

// викликається після завершення переходу enter.
function onAfterEnter(el) {}

// викликається, коли перехід enter скасовано до завершення.
function onEnterCancelled(el) {}

// викликається перед виходом.
// у більшості випадків ви повинні просто використовувати хук для виходу.
function onBeforeLeave(el) {}

// викликається, коли починається вихід.
// використовуйте це для запуску анімації виходу.
function onLeave(el, done) {
  // викликає зворотний виклик done, щоб вказати кінець переходу.
  // необов'язковий, якщо використовується в поєднанні з CSS.
  done()
}

// викликається, коли вихід закінчився, і
// елемент видалено з DOM.
function onAfterLeave(el) {}

// доступно лише з переходами v-show.
function onLeaveCancelled(el) {}
js
export default {
  // ...
  methods: {
    // викликається перед тим, як елемент буде вставлено в DOM.
    // використовуйте це, щоб встановити стан "enter-from" елемента.
    onBeforeEnter(el) {},

    // викликається з наступним кадром після вставки елемента.
    // використовуйте це, щоб почати анімацію виходу.
    onEnter(el, done) {
      // викликає зворотний виклик done, щоб вказати кінець переходу.
      // необов'язковий, якщо використовується в поєднанні з CSS.
      done()
    },

    // викликається після завершення переходу enter.
    onAfterEnter(el) {},
    onEnterCancelled(el) {},

    // викликається перед виходом.
    // у більшості випадків ви повинні просто використовувати хук для виходу.
    onBeforeLeave(el) {},

    // викликається, коли починається вихід.
    // використовуйте це для запуску анімації виходу.
    onLeave(el, done) {
      // викликає зворотний виклик done, щоб вказати кінець переходу
      // необов'язковий, якщо використовується в поєднанні з CSS
      done()
    },

    // викликається, коли вихід закінчився, і
    // елемент видалено з DOM.
    onAfterLeave(el) {},

    // доступно лише з переходами v-show.
    onLeaveCancelled(el) {}
  }
}

Ці хуки можна використовувати в поєднанні з переходами/анімаціями CSS або окремо.

При використанні лише JavaScript переходів, як правило, гарною ідеєю буде додати властивість :css="false". Це явно вказує Vue пропустити автоматичне виявлення переходів CSS. Окрім трохи більшої продуктивності, це також запобігає випадковому втручанню правил CSS у перехід:

template
<Transition
  ...
  :css="false"
>
  ...
</Transition>

Завдяки :css="false" ми також несемо повну відповідальність за контроль завершення переходу. У цьому випадку зворотні виклики done потрібні для хуків @enter і @leave. В іншому випадку хуки будуть викликані синхронно, і перехід завершиться негайно.

Ось демонстрація використання бібліотеки GreenSock для виконання анімації. Звичайно, ви можете використовувати будь-яку іншу бібліотеку анімації, наприклад Anime.js або Motion One.

Багаторазові переходи

Переходи можна повторно використовувати через систему компонентів Vue. Щоб створити багаторазовий перехід, ми можемо створити компонент, який обгортає компонент <Transition> і передає вниз вміст слота:

vue
<!-- MyTransition.vue -->
<script>
// JavaScript логіка хука...
</script>

<template>
  <!-- обернути вбудований компонент Transition -->
  <Transition
    name="my-transition"
    @enter="onEnter"
    @leave="onLeave">
    <slot></slot> <!-- передати вміст слота -->
  </Transition>
</template>

<style>
/*
  необхідний CSS...
  примітка: уникайте використання <style scoped>
  тут це не стосується вмісту слота.
*/
</style>

Тепер MyTransition можна імпортувати та використовувати так само, як і вбудовану версію:

template
<MyTransition>
  <div v-if="show">Привіт</div>
</MyTransition>

Перехід появи

Якщо ви також хочете застосувати перехід до початкового рендерингу вузла, ви можете додати властивість appear:

template
<Transition appear>
  ...
</Transition>

Перехід між елементами

Окрім перемикання елемента за допомогою v-if / v-show, ми також можемо переходити між двома елементами за допомогою v-if / v-else / v-else-if, якщо ми переконаємося, що в будь-який момент відображається лише один елемент:

template
<Transition>
  <button v-if="docState === 'saved'">Редагувати</button>
  <button v-else-if="docState === 'edited'">Зберегти</button>
  <button v-else-if="docState === 'editing'">Скасувати</button>
</Transition>
Натисніть, щоб циклічно переходити між станами:

Спробуйте в пісочниці

Режими переходу

У попередньому прикладі вхідні та вихідні елементи анімовані одночасно, і нам довелося зробити їх position: absolute, щоб уникнути проблеми з макетом, коли обидва елементи присутні в DOM.

Однак у деяких випадках це не варіант або просто не бажана поведінка. Ми можемо захотіти, щоб вихідний елемент анімувався спочатку, а вхідний елемент вставлявся лише після завершення анімації виходу. Оркеструвати таку анімацію вручну було б дуже складно – на щастя, ми можемо ввімкнути таку поведінку, передавши <Transition> реквізиту mode:

template
<Transition mode="out-in">
  ...
</Transition>

Ось попередня демонстрація з mode="out-in":

Натисніть, щоб циклічно переходити між станами:

<Transition> також підтримує mode="in-out", хоча він використовується набагато рідше.

Перехід між компонентами

<Transition> також можна використовувати з динамічних компонентів:

template
<Transition name="fade" mode="out-in">
  <component :is="activeComponent"></component>
</Transition>
Компонент A

Динамічні переходи

Реквізити <Transition> такі як name також можуть бути динамічними! Це дозволяє нам динамічно застосовувати різні переходи на основі зміни стану:

template
<Transition :name="transitionName">
  <!-- ... -->
</Transition>

Це може бути корисним, якщо ви визначили переходи/анімації CSS за допомогою угоди про класи переходів Vue і хочете перемикатися між ними.

Ви також можете застосувати різну поведінку в хуках переходів JavaScript на основі поточного стану вашого компонента. Нарешті, найкращим способом створення динамічних переходів є компоненти переходів для багаторазового використання, які приймають підказки для зміни характеру переходів, які будуть використовуватися. Це може здатися дивним, але єдиним обмеженням є ваша уява.


Пов'язані

Перехід has loaded