Vue一個案例引發「動畫」的使用總結

六小登登發表於2019-03-04

專案開發中動畫有著很重要的作用,而且也是用到的地方非常多,例如:滑鼠的進入離開,彈窗效果,元件的顯示隱藏,列表的切換等等,可以說我們網頁上的動畫無處不在,也有人說了,這些東西也可以不使用動畫。

對,你說的沒錯可以不使用,但是,首先你要說服你的產品經理我們能不能簡單點,不搞這麼多虛的來點實際的,說完之後我估計你們倆得立馬乾起來,其次,在你的網頁上不使用動畫不夠逼格啊,而且我們們的網頁也不夠生動,沒有活力,由此可見動畫的不可或缺性。

上面只是開個玩笑,下面我們們進入主題,看看 Vue 中如何更好更簡單的新增動畫。

首先,Vue 在插入,修改或者移除 DOM 時,提供了多種不同的新增動畫的方法,在 Vue 中我們使用 <transition><transition-group> 元件時,Vue 會給我們提供一些內建的 CSS 類與 JS 鉤子函式。

先來看看我們要實現一個什麼樣子的案例效果

Vue一個案例引發「動畫」的使用總結

圖中的例子是一個非常常見的圖片切換效果,不過在這個例子中我們只是單純的實現圖片的切換,看起來非常的生硬,沒有任何的過渡效果,下面我們來給圖片加一點動畫的效果,讓它看起來非常的有逼格。

CSS 過渡

<transition> 包裹的元件,在元件的不同階段會產生不同的 class 類名進行切換

  • v-enter/v-leave:動畫的第一幀
  • v-enter-acive/v-leave-active:動畫執行的階段,一些過渡屬性會放置在這裡,如:時間,延遲等
  • v-enter-to/v-leave-to:動畫結束,最後一幀

官網上的一張圖片非常友好的展示了這個切換的過程。

Vue一個案例引發「動畫」的使用總結

v- 是 Vue 中預設的類名字首,我們在使用的過程中如果一直使用預設的命名方式的話,必然會導致一些衝突,所以 Vue 給我們提供了一個自定義命名的方案,我們只需要給 <transition> 新增一個 name 屬性即可。

既然我們知道了方法,我們就來給它加一個簡單的動畫。

<template>
<ul class="tabs-list">
  <li 
    v-for="tab in tabs"
    :key="tab.id"
    :class="{active: tabOn === tab.id}" 
  >
    <a
      @mouseover="tabOn = tab.id"
      :href="tab.url" target="_blank"
    >
      {{tab.name}}
      <transition name="flip">
        <img v-show="tabOn === tab.id" :src="tab.imgUrl">
      </transition>
    </a>
  </li>
</ul>
<template>
<style lang="scss" scoped>
.flip-enter-active {
  transition: transform 1s;
}
.flip-leave-active {
  transition: transform 1s;
}
.flip-enter,
.flip-leave-to {
  transform: scaleY(0);
}
</style>
複製程式碼

Vue一個案例引發「動畫」的使用總結

CSS 動畫

與上面 CSS 過渡不同的是,我們這裡說的 CSS 動畫是利用 @keyframes 來建立與上面類似的動畫效果。

<style lang="scss" scoped>
@keyframes scaleY-in {
  0% {
    transform: scaleY(0);
  }
  50% {
    transform: scaleY(0.5);
  }
  100% {
    transform: scaleY(1);
  }
}
.flip-enter-active {
  animation: scaleY-in 1s;
}

.flip-leave-active {
  animation: scaleY-in 1s reverse;
}
</style>
複製程式碼

使用第三方動畫庫

Vue 中給我們提供了自定義 CSS 類名的方法,非常好的支援了與第三方動畫庫的結合。

  • enter-class / leave-class
  • enter-active-class / leave-active-class
  • enter-to-class / leave-to-class

上面兩個動畫都是我們自己動手寫出來的,但是有些時候我們自己手寫的並不是那麼完美,或者專案的時間比較緊張,這個時候選擇第三方庫就是一個比較好的方案。我們繼續利用 Animate.css 動畫庫修改我們上面的例子。

<transition 
    name="flip"
    enter-active-class="animated rotateIn"
    leave-active-class="animated rotateOut"
>
    <img v-show="tabOn === tab.id" :src="tab.imgUrl">
</transition>
複製程式碼

Vue一個案例引發「動畫」的使用總結

JavaScript 動畫

Vue 中還給我們提供了一些鉤子函式,我們可以使用 JavaScript 鉤子函式構建動畫。

<transition
  @before-enter="beforeEnter"
  @enter="enter"
  @after-enter="afterEnter"
  @enter-cancelled="enterCancelled"

  @before-leave="beforeLeave"
  @leave="leave"
  @after-leave="afterLeave"
  @leave-cancelled="leaveCancelled"
  :css="false"
>
</transition>
複製程式碼

所有鉤子都會傳入一個 el(元素)引數,enter/leave 函式還會傳入一個 done 函式作為引數。它會告知我們的動畫完成,我們繫結了 css 為 false,告訴元件跳過 CSS 的檢測,使用 JavaScript。

我們結合 Velocity.js 動畫,來修改完成我們的動畫效果。

<transition 
    @enter="enter"
    @leave="leave"
    :css="false"
>
    <img v-show="tabOn === tab.id" :src="tab.imgUrl">
</transition>
<script>
methods: {
    enter(el, done) {
      Velocity(el, { scaleY: "0" });
      Velocity(el, { scaleY: "0.5" }, { duration: 1000 });
      Velocity(el, { scaleY: "1" }, { complete: done });
    },
    leave: function(el, done) {
      Velocity(el, { scaleY: "1" });
      Velocity(el, { scaleY: "0.5" }, { duration: 1000 });
      Velocity(el, { scaleY: "0" }, { complete: done });
    }
}
</script>
複製程式碼

過渡模式

我們再來回頭看看上面的例子,不管我們使用何種方式實現的動畫,你會發現一個問題就是,動畫在切換的時候兩者(進入/離開)是同時進行的,有些時候,我們並不希望產生這種效果,對我們的動畫效果非常的不友好,比如我們看看下面的這個例子。

<template>
<div class="translate-container" @click="clickHandler">
  <transition name="slide">
    <img v-if="isShow" src="./feature/03.jpg" key="first">
    <img v-else src="./feature/04.jpg" key="second">
  </transition>
</div>
</template>
<script>
export default {
  methods: {
    clickHandler() {
      this.isShow = !this.isShow;
    }
  }
}
</script>
<style lang="scss" scoped>
    .slide-enter-active,
    .slide-leave-active {
      transition: all 0.5s;
    }
    .slide-leave-to,
    .slide-enter {
      transform: scaleY(0);
    }
</style>
複製程式碼

Vue一個案例引發「動畫」的使用總結

很顯然,這種是非常不好的效果,值得高興的是 Vue 中給我們提供了一個解決方案-- 過渡模式,我們不需要增加額外的程式碼,只需要修改下特性即可。

Vue 給我們提供了兩種過渡模式。

  • in-out:新元素先進行過渡,完成之後當前元素過渡離開。
  • out-in:當前元素先進行過渡,完成之後新元素過渡進入

過渡模式只會在相互切換的元素中才會生效

<transition name="fade" mode="out-in"></transition>

<transition name="fade" mode="in-out"></transition>
複製程式碼

下面我們就用過渡模式修改我們上面的案例。

<transition name="slide" mode="out-in">
    <img v-if="isShow" src="./feature/03.jpg" key="first">
    <img v-else src="./feature/04.jpg" key="second">
</transition>
複製程式碼

Vue一個案例引發「動畫」的使用總結

總結

Vue 給我們提供了比較直觀靈活的 API,方便我們在專案中新增動畫的效果。

Vue 中除了這些單元素的動畫以外還提供了<transition-group> 給我的列表(使用v-for 時的場景)新增動畫,喜歡動畫的小夥伴可以動手去嘗試繪製一些自己喜歡的動畫。

文中如有不足之處,歡迎留言指正,如果本文對你有幫助,歡迎轉發點贊。

Vue一個案例引發「動畫」的使用總結

相關文章