本文主要歸納在 Vuejs 學習過程中對於 Vuejs 動畫效果的各個相關要點。由於本人水平有限,如文中出現錯誤請多多包涵並指正,感謝。如果需要看更清晰的代碼高亮,請跳轉至我的個人站點的 深入理解 Vuejs 動畫效果 查看本文。
Vue 中的 CSS 動畫原理
將標簽外部添加 transition
標簽,將其包裹起來。他的原理圖如下,即當一個元素被transition
包裹之后,Vue 會自動分析元素的 CSS 樣式,然后構建一個動畫流程。
下面示例圖中的線和點,就可以稱之為一個動畫流程。Vue 會在動畫即將執行的瞬間,往內部被包裹的的 div
上增添兩個 class
名,分別是 fade-enter
和 fade-enter-active
。當動畫第一幀執行結束之后;Vue 會在動畫執行到第二幀的時候,把之前添加的 fade-enter
這個 class
去除,然后再增加一個 fade-enter-to
的 class
名;接着動畫繼續執行,執行到結束的瞬間,Vue 會把之前添加的 fade-enter-active
和 fade-enter-to
兩個 class
都去除掉。

當動畫從顯示狀態變為隱藏狀態時,原理圖如下,流程跟上相似:

Vue 過渡動畫案例代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Vue中的css動畫原理</title> <script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script> <style> .fade-enter { opacity: 0; } .fade-enter-active { transition: opacity 2s; } .fade-leave-to { opacity: 0; } .fade-leave-active { transition: opacity 2s; } </style> </head> <body> <div id="app"> <transition name="fade"> <div v-if="show"> hello world </div> </transition> <button @click="handleClick">切換</button> </div> <script> var vm = new Vue({ el: "#app", data: { show: true }, methods: { handleClick: function(){ this.show = ! this.show } } }) </script> </body> </html>
JSbin 預覽
因為 transition
上設置的 name
屬性名為 fade
。所以 style
中 CSS 樣式為 fade
開頭。如果 transition
上沒有設置 name
屬性名,那么style
中 CSS 樣式為 v
開頭,即 v-enter
、v-center-active
等。
Vue 中使用 CCS3 @keyframes 動畫
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title> keyframes 動畫 </title> <script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script> <style> @keyframes bounce-in { 0% { transform: scale(0); } 50% { transform: scale(1.5); } 100% { transform: scale(1); } } .fade-enter-active { transform-origin: left center; animation: bounce-in 1s; } .fade-leave-active { transform-origin: left center; animation: bounce-in 1s reverse; } </style> </head> <body> <div id="app"> <transition name="fade"> <div v-if="show"> hello world </div> </transition> <button @click="handleClick">切換</button> </div> <script> var vm = new Vue({ el: "#app", data: { show: true }, methods: { handleClick: function(){ this.show = ! this.show } } }) </script> </body> </html>
自定義
如果 CSS 樣式沒有進行這種方式命名,而是我們通過自定義的方式命名的,如下:
.active { transform-origin: left center; animation: bounce-in 1s; } .leave { transform-origin: left center; animation: bounce-in 1s reverse; }
那么在 transition
標簽里面就要對這個自定義的 class
進行聲明。
<transition name="fade" enter-active-class="active" leave-active-class="leave" > <div v-if="show"> hello world </div> </transition>
Animate.css 庫
Animate.css庫官網 提供了眾多 CSS 效果。引入和使用的原理和 iconfont
類似。
- 下載該庫之后,在
link
標簽下引入。
<link rel="stylesheet" type="text/css" href="./animate.css">
- 然后在
transition
標簽中定義enter-active-class
與leave-active-class
為animate
庫中相應的樣式。下面示例即是入場動畫使用swing
,出場動畫使用shake
。
<transition name="fade" enter-active-class="animated swing" leave-active-class="animated shake" > <div v-if="show"> hello world </div> </transition>
值得注意的是,當引入並使用 Animate.css 庫時,必須使用自定義 class
名的形式使用 Animate.css。同時,class
當中必須包含一個 animated
,然后再將相應的效果添加到 animated
之后。
appear
上面一節的示例中,當我們在頁面剛剛刷新時(第一次元素顯示時)也加上一些動畫效果,則需要加上 appear
和 appear-active-class
。
<transition name="fade" appear enter-active-class="animated swing" leave-active-class="animated shake" appear-active-class="animated swing" > <div v-if="show"> hello world </div> </transition>
同時使用過渡和動畫
之前提到的 Animate.css 庫 提供的動畫是 @keyframes
類型 CSS3 的動畫。假如我們希望動畫不僅僅只有 @keyframes
的效果,還另外有過渡的動畫效果時。這個時候我們可以這樣進行代碼的編寫。
即在 animated
的 class
之后再添加 過渡動畫的 CSS class
。
.fade-enter, .fade-leave-to { opacity: 0; } .fade-enter-active, .fade-leave-active { transition: opacity 3s; }
<transition type="transition" name="fade" appear enter-active-class="animated swing fade-enter-active" leave-active-class="animated shake fade-leave-active" appear-active-class="animated swing" > <div v-if="show"> hello world </div> </transition>
動畫執行時長: 值得注意的是,
animate
之中的動畫執行是 1s,當過渡動畫超過 1s 時,在transition
里面添加屬性type
,就會以transition
里面動畫的時長為動畫執行時長。同樣的,這個執行時長也可以自定義,通過:duration
屬性來進行設置,例如當屬性被設置為:duration="10000"
,即時長為 10s。除此之外,還可以單獨設置出場、入場動畫為不同的時長,:duration="{ enter: 5000, leave: 10000 }"
。
Vue 中的 JS 動畫
動畫鈎子
before-enter
before-enter
會接收到一個參數 el
,即指的是動畫 transition
包裹的標簽。
<div id="app"> <transition name="fade" @before-enter="handleBeforeEnter"> <div v-show="show"> hello world </div> </transition> <button @click="handleClick">切換</button> </div>
var vm = new Vue({ el: "#app", data: { show: true }, methods: { handleClick: function(){ this.show = ! this.show }, // 接收到一個參數 el 代指被包裹的標簽 handleBeforeEnter: function(el){ el.style.color = 'red' } } })
enter
enter
會接收兩個參數,一個為 el
,指的仍然是動畫 transition
包裹的標簽。 一個為 done
,是一個回調函數。
<div id="app"> <transition name="fade" @before-enter="handleBeforeEnter" @enter="handleEnter"> <div v-show="show"> hello world </div> </transition> <button @click="handleClick">切換</button> </div>
var vm = new Vue({ el: "#app", data: { show: true }, methods: { handleClick: function(){ this.show = ! this.show }, handleBeforeEnter: function(el){ el.style.color = 'red' }, handleEnter: function(el, done){ setTimeout(() => { el.style.color = 'green' done() },2000) } } })
上面 handleEnter
中的 setTimeout
執行完之后,調用了 done()
。而當done()
被調用的時候,Vue 又會觸發一個 after-enter
事件。
after-enter
after-enter
也要接收到參數 el
。
<div id="app"> <transition name="fade" @before-enter="handleBeforeEnter" @enter="handleEnter" @after-enter="handleAfterEnter" > <div v-show="show"> hello world </div> </transition> <button @click="handleClick">切換</button> </div>
var vm = new Vue({ el: "#app", data: { show: true }, methods: { handleClick: function(){ this.show = ! this.show }, handleBeforeEnter: function(el){ el.style.color = 'red' }, handleEnter: function(el, done){ setTimeout(() => { // 2s 之后改變顏色 el.style.color = 'green' },2000) setTimeout(() => { // 4s 之后 done() done() },4000) }, handleAfterEnter: function(el){ el.style.color = "#000" } } })
出場動畫鈎子
相應的。出場動畫的鈎子函數為 before-leave
、leave
和 after-leave
。用法與上面所講的入場動畫鈎子函數相似。
動畫鈎子示例
velocity.js 動畫庫
在 velocityjs 官網 下載 velocity.js
文件。並通過 script
標簽引入 velocity.js
。
按照下面的寫法,將 el
、{opacity: 1}
、{duration: 1000, complete: done}
當做參數傳遞給 Velocity
。
var vm = new Vue({ el: "#app", data: { show: true }, methods: { handleClick: function(){ this.show = ! this.show }, handleBeforeEnter: function(el){ el.style.opacity = 0 }, handleEnter: function(el, done){ Velocity(el, {opacity: 1}, {duration: 1000, complete: done}) }, handleAfterEnter: function(el){ alert('動畫結束') } } })
多個元素與組件的過渡動畫
多個元素間過渡動畫
在下面的示例中,之所以加上 key
值,是為了讓 Vue 不去復用 DOM,達到我們想要的效果。給 transition
添加 mode
屬性,out-in
、in-out
分別表示多個屬性切換時候的不同的出場、入場順序效果。
<div id="app"> <transition mode="out-in" name="fade"> <div v-if="show" key="hello">hello world</div> <div v-else key="bye">Bye World</div> </transition> <button @click="handleClick">切換</button> </div>
多個組件間過渡動畫
在下面的示例中,兩個組件通過 button
點擊之后觸發的事件,進行內容的顯示和隱藏的切換。
.fade-enter, .fade-leave-to { opacity: 0; } .fade-enter-active, .fade-leave-active { transition: opacity 1s; }
<div id="app"> <transition mode="out-in" name="fade"> <child v-if="show"></child> <child-one v-else></child-one> </transition> <button @click="handleClick">切換</button> </div>
Vue.component('child',{ template: '<div>child</div>' }) Vue.component('child-one',{ template: '<div>child-one</div>' }) var vm = new Vue({ el: "#app", data: { show: true }, methods: { handleClick: function(){ this.show = ! this.show } } })
動態組件
除此之外也可以參考之前 深入理解 Vuejs 組件 中動態組件的方式。給 component
外邊的 transition
添加 mode
。
列表過渡
參照下面 JSbin 中的示例,構造了一段代碼,簡單的實現了一個點擊 button
按鈕添加列表展示數據的 demo。現在我們要針對一整個列表,在增加或者刪除的時候實現過渡效果。這里就需要一個新的標簽 transition-group
。

添加 transition-group
等同於給每一個 div
之外添加 transition
。相當於把列表的過渡轉化成單個元素標簽的過渡。
除此之外跟前幾節的過渡動畫一樣,需要在 style
中添加相應的樣式。
動畫封裝
當需要頻繁使用一個動畫效果的時候,我們將動畫封裝到一個組件之中是很好的方法。結合之前的動畫鈎子,可以實現將模板、樣式都封裝到組件的效果。當需要使用的時候,直接使用該組件模板標簽,並添加相應的 show
屬性即可。
<div id="app"> <fade :show="show"> <div>hello world</div> </fade> <fade :show="show"> <h1>hello world</h1> </fade> <button @click="handleClick">toggle</button> </div>
// 封裝 fade 子組件 Vue.component('fade',{ props: ['show'], // 接收父組件傳遞過來的 show 參數 // template 模板,並使用動畫鈎子將樣式封裝在函數中 template: ` <transition @before-enter="handleBeforeEnter" @enter="handleEnter" @after-enter="handleAfterEnter"> <slot v-if="show"></slot> </transition> `, methods: { handleBeforeEnter: function(el){ el.style.color = 'red' }, handleEnter: function(el,done){ setTimeout(() => { el.style.color = 'green' },2000) setTimeout(() => { done() },4000) }, handleAfterEnter: function(el){ el.style.color = "#000" } } }) var vm = new Vue({ el: "#app", data: { show: true }, methods: { handleClick: function(){ this.show = ! this.show } } })