天天看點

Vue 過渡 & 動畫

概述

Vue 在插入、更新或者移除 DOM 時,提供多種不同方式的應用過渡效果。 包括以下工具:

  • 在 CSS 過渡和動畫中自動應用 class
  • 可以配合使用第三方 CSS 動畫庫,如 Animate.css
  • 在過渡鈎子函數中使用 JavaScript 直接操作 DOM
  • 可以配合使用第三方 JavaScript 動畫庫,如 Velocity.js

單元素/元件的過渡

Vue 提供了 transition 的封裝元件,在下列情形中,可以給任何元素群組件添加 entering/leaving 過渡。

  • 條件渲染 (使用 v-if)
  • 條件展示 (使用 v-show)
  • 動态元件
  • 元件根節點

下面是一個典型的例子:

<div id="demo">
  <button v-on:click="show = !show">
    Toggle
  </button>
  <transition name="fade">
    <p v-if="show">hello</p>
  </transition>
</div>
           
new Vue({
  el: '#demo',
  data: {
    show: true
  }
})
           
.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}
           

當插入或删除包含在 transition 元件中的元素時,Vue 将會做以下處理:

  • 自動嗅探目标元素是否應用了 CSS 過渡或動畫,如果是,在恰當的時機添加/删除 CSS 類名。
  • 如果過渡元件提供了 JavaScript 鈎子函數,這些鈎子函數将在恰當的時機被調用。
  • 如果沒有找到 JavaScript 鈎子并且也沒有檢測到 CSS 過渡/動畫,DOM 操作 (插入/删除) 在下一幀中立即執行。(注意:此指浏覽器逐幀動畫機制,和 Vue 的 nextTick 概念不同)

過渡的類名

在進入/離開的過渡中,會有 6 個 class 切換。

  • v-enter:定義進入過渡的開始狀态。在元素被插入時生效,在下一個幀移除。
  • v-enter-active:定義過渡的狀态。在元素整個過渡過程中作用,在元素被插入時生效,在 transition/animation 完成之後移除。這個類可以被用來定義過渡的過程時間,延遲和曲線函數。
  • v-enter-to: 定義進入過渡的結束狀态。在元素被插入一幀後生效 (與此同時 v-enter 被删除),在 transition/animation 完成之後移除。
  • v-leave: 定義離開過渡的開始狀态。在離開過渡被觸發時生效,在下一個幀移除。
  • v-leave-active:定義過渡的狀态。在元素整個過渡過程中作用,在離開過渡被觸發後立即生效,在 transition/animation 完成之後移除。這個類可以被用來定義過渡的過程時間,延遲和曲線函數。
  • v-leave-to: 定義離開過渡的結束狀态。在離開過渡被觸發一幀後生效 (與此同時 v-leave 被删除),在 transition/animation 完成之後移除。

對于這些在 enter/leave 過渡中切換的類名,v- 是這些類名的字首。使用 <transition name="my-transition"> 可以重置字首,比如 v-enter 替換為 my-transition-enter。

v-enter-active 和 v-leave-active 可以控制 進入/離開 過渡的不同階段,在下面章節會有個示例說明。

CSS 過渡

常用的過渡都是使用 CSS 過渡。

下面是一個簡單例子:

<div id="example-1">
  <button @click="show = !show">
    Toggle render
  </button>
  <transition name="slide-fade">
    <p v-if="show">hello</p>
  </transition>
</div>
           
new Vue({
  el: '#example-1',
  data: {
    show: true
  }
})
           
/* 可以設定不同的進入和離開動畫 */
/* 設定持續時間和動畫函數 */
.slide-fade-enter-active {
  transition: all .3s ease;
}
.slide-fade-leave-active {
  transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active for below version 2.1.8 */ {
  transform: translateX(10px);
  opacity: 0;
}
           

CSS 動畫

CSS 動畫用法同 CSS 過渡,差別是在動畫中 v-enter 類名在節點插入 DOM 後不會立即删除,而是在 animationend 事件觸發時删除。

自定義過渡的類名

  • enter-class
  • enter-active-class
  • enter-to-class (2.1.8+)
  • leave-class
  • leave-active-class
  • leave-to-class (2.1.8+)

他們的優先級高于普通的類名,這對于 Vue 的過渡系統和其他第三方 CSS 動畫庫,如 Animate.css 結合使用十分有用。

<link href="https://cdn.jsdelivr.net/npm/[email protected]" target="_blank" rel="external nofollow"  rel="stylesheet" type="text/css">

<div id="example-3">
  <button @click="show = !show">
    Toggle render
  </button>
  <transition
    name="custom-classes-transition"
    enter-active-class="animated tada"
    leave-active-class="animated bounceOutRight"
  >
    <p v-if="show">hello</p>
  </transition>
</div>
           
new Vue({
  el: '#example-3',
  data: {
    show: true
  }
})
           

同時使用過渡和動畫

Vue 為了知道過渡的完成,必須設定相應的事件監聽器。它可以是 transitionend 或 animationend ,這取決于給元素應用的 CSS 規則。如果你使用其中任何一種,Vue 能自動識别類型并設定監聽。

但是,在一些場景中,你需要給同一個元素同時設定兩種過渡動效,比如 animation 很快的被觸發并完成了,而 transition 效果還沒結束。在這種情況中,你就需要使用 type 特性并設定 animation 或 transition 來明确聲明你需要 Vue 監聽的類型。

顯性的過渡持續時間

在很多情況下,Vue 可以自動得出過渡效果的完成時機。預設情況下,Vue 會等待其在過渡效果的根元素的第一個 transitionend 或 animationend 事件。然而也可以不這樣設定——比如,我們可以擁有一個精心編排的一序列過渡效果,其中一些嵌套的内部元素相比于過渡效果的根元素有延遲的或更長的過渡效果。

在這種情況下你可以用 <transition> 元件上的 duration 屬性定制一個顯性的過渡持續時間 (以毫秒計):

<transition :duration="1000">...</transition>
           

你也可以定制進入和移出的持續時間:

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

JavaScript 鈎子

可以在屬性中聲明 JavaScript 鈎子:

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"

  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>
           
// ...
methods: {
  // --------
  // 進入中
  // --------

  beforeEnter: function (el) {
    // ...
  },
  // 此回調函數是可選項的設定
  // 與 CSS 結合時使用
  enter: function (el, done) {
    // ...
    done()
  },
  afterEnter: function (el) {
    // ...
  },
  enterCancelled: function (el) {
    // ...
  },

  // --------
  // 離開時
  // --------

  beforeLeave: function (el) {
    // ...
  },
  // 此回調函數是可選項的設定
  // 與 CSS 結合時使用
  leave: function (el, done) {
    // ...
    done()
  },
  afterLeave: function (el) {
    // ...
  },
  // leaveCancelled 隻用于 v-show 中
  leaveCancelled: function (el) {
    // ...
  }
}
           

這些鈎子函數可以結合 CSS transitions/animations 使用,也可以單獨使用。

當隻用 JavaScript 過渡的時候, 在 enter 和 leave 中,回調函數 done 是必須的 。否則,它們會被同步調用,過渡會立即完成。

推薦對于僅使用 JavaScript 過渡的元素添加 v-bind:css="false",Vue 會跳過 CSS 的檢測。這也可以避免過渡過程中 CSS 的影響。

初始渲染的過渡

可以通過 appear 特性設定節點在初始渲染的過渡。

<transition appear>
  <!-- ... -->
</transition>
           

這裡預設和進入/離開過渡一樣,同樣也可以自定義 CSS 類名。

<transition
  appear
  appear-class="custom-appear-class"
  appear-to-class="custom-appear-to-class" (2.1.8+)
  appear-active-class="custom-appear-active-class"
>
  <!-- ... -->
</transition>
           

自定義 JavaScript 鈎子:

<transition
  appear
  v-on:before-appear="customBeforeAppearHook"
  v-on:appear="customAppearHook"
  v-on:after-appear="customAfterAppearHook"
  v-on:appear-cancelled="customAppearCancelledHook"
>
  <!-- ... -->
</transition>
           

繼續閱讀