Vue 在插入、更新或者移除 DOM 時,提供多種不同方式的應用過渡效果。
包括以下工具:
- 在 CSS 過渡和動畫中自動應用 class
- 可以配合使用第三方 CSS 動畫庫,如 Animate.css
- 在過渡鈎子函數中使用 JavaScript 直接操作 DOM
- 可以配合使用第三方 JavaScript 動畫庫,如 Velocity.js
下面分別從這個4個工具來學習Vue動畫效果。
一、單元素/組件的過渡
Vue 提供了 transition
的封裝組件,在下列情形中,可以給任何元素和組件添加進入/離開過渡
- 條件渲染 (使用
v-if
) - 條件展示 (使用
v-show
) - 動態組件
- 組件根節點
一個典型的例子:
Html文件
<div id="app"> <transition name="fade"> <div v-if="show"> Hello world. </div> </transition> <button @click="handleClick">切換</button> </div>
js文件
<script> // 1. 創建Vue的實例 let vm = new Vue({ el:'#app', data:{ show:false }, methods:{ handleClick:function(){ this.show = !this.show } } }); </script>
css文件
<style> .fade-enter-active, .fade-leave-active { transition: opacity 2s; } .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0; } </style>
這個例子的效果為:點擊切換,文字會淡入淡出。
實現原理:
1、通過使用transition組件后, Vue 將會做以下處理:
- 自動嗅探目標元素是否應用了 CSS 過渡或動畫,如果是,在恰當的時機添加/刪除 CSS 類名。
- 如果過渡組件提供了 JavaScript 鈎子函數,這些鈎子函數將在恰當的時機被調用。
- 如果沒有找到 JavaScript 鈎子並且也沒有檢測到 CSS 過渡/動畫,DOM 操作 (插入/刪除) 在下一幀中立即執行。(注意:此指瀏覽器逐幀動畫機制,和 Vue 的
nextTick
概念不同)
2、動畫進入時,Vue會添加CSS類,如果沒有使用name="fade"的話,類名為v-fade-enter、v-fade-eneter-active等。
第一幀動畫,會自動添加fade-enter和fade-enter-active類
第二幀動畫,會去掉fade-enter類,添加fade-enter-to類
第三幀動畫,會去掉所有enter類
3、動畫在離開時同樣會添加或刪除CSS類
二、Vue使用animate.css動畫庫
1、使用自定義類
效果為:進入或離開都會有拉升效果。
注意:這里我們使用了
name="bounce"替換了默認的fade。當然,如果沒有fade的話,也會有v-作為默認開頭。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> @keyframes bounce-in { 0% { transform: scale(0); } 50% { transform: scale(1.5); } 100% { transform: scale(1); } } .bounce-enter-active { animation: bounce-in .5s; } .bounce-leave-active { animation: bounce-in .5s reverse; } </style> </head> <body> <div id="app"> <transition name="bounce"> <div v-if="show"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus. </div> </transition> <button @click="handleClick">切換</button> </div> <script src="js/vue.js"></script> <script> // 1. 創建Vue的實例 let vm = new Vue({ el:'#app', data:{ show:false }, methods:{ handleClick:function(){ this.show = !this.show } } }); </script> </body> </html>
我們這里還可以使用自定義類:
既然我們可以使用自定義class,那么我們就可以使用開源的第三方CSS庫,比如animate.css庫。
https://daneden.github.io/animate.css/
使用很簡單,直接替換上面我們自定義的class就行。
使用animate.css注意事項:
1、必須使用自定義class的模式
enter-active-class=""
2、animated類放在前面,且是必須的
三、Vue中同時使用過渡和動畫
1、初次動畫效果
上面例子中,我們初次進入的時候沒有動畫效果,我們可以做如下修改:
2、如果我們希望在上面的例子中還加入一開始我們說的過渡效果,那該怎么做呢?
1、因為animate.css有一個自己的動畫效果時長,fade也有一個opacity,那么以哪一個為准呢?我們可以使用type="transition"來確定哪個為准。
2、我們也可以自己設定動畫效果時長樣式:duration里面的enter為進入時長,leave為動畫離開時長,都是針對過渡效果的。
四、Vue中的js動畫配合使用第三方動畫庫(Velocity.js)
Html
<div id="app"> <transition name="fade" @before-enter="beforeEnter" @enter="enter" > <div v-if="show"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus. </div> </transition> <button @click="handleClick">切換</button> </div>
Js
methods:{ handleClick:function(){ this.show = !this.show }, beforeEnter: function (el) { el.style.opacity = 0 el.style.transformOrigin = 'left' }, enter: function (el, done) { Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 }) Velocity(el, { fontSize: '1em' }, { complete: done }) }, }
五、多個元素或組件的過渡動畫
1、多個元素的過渡動畫實現
Html
<div id="app"> <transition name="fade" mode="in-out"> <div v-if="show" key='one'>組件1</div> <div v-else key='two'>組件2</div> </transition> <button @click="handleClick">切換</button> </div>
style
<style> .fade-enter-active, .fade-leave-active { transition: opacity 1s; } .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0; } </style>
注意:這里需要綁定一個key,因為vue會復用,所以不加key就不會有效果。
2、多個組件的過渡動畫實現
Html
<div id="app"> <transition name="fade" > <child-one v-if="show"></child-one> <child-two v-else></child-two> </transition> <button @click="handleClick">切換</button> </div>
js
<script> Vue.component('child-one',{ template:'<div>child-one</div>' }) Vue.component('child-two',{ template:'<div>child-two</div>' }) // 1. 創建Vue的實例 let vm = new Vue({ el:'#app', data:{ show:false }, methods:{ handleClick:function(){ this.show = !this.show } } }); </script>
css
<style> .fade-enter-active, .fade-leave-active { transition: opacity .4s; } .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0; } </style>
我們可以通過Vue自帶的compoent標簽實現動態組件,data中show改成type,type:‘child-one’
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .fade-enter-active, .fade-leave-active { transition: opacity .4s; } .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0; } </style> </head> <body> <div id="app"> <transition name="fade" > <component :is="type"></component> </transition> <button @click="handleClick">切換</button> </div> <script src="js/vue.js"></script> <script> Vue.component('child-one',{ template:'<div>child-one</div>' }) Vue.component('child-two',{ template:'<div>child-two</div>' }) // 1. 創建Vue的實例 let vm = new Vue({ el:'#app', data:{ type:'child-one' }, methods:{ handleClick:function(){ this.type = this.type==='child-one'?'child-two':'child-one' } } }); </script> </body> </html>
六、Vue中列表的過渡動畫
當我們希望對列表進行過渡效果時,使用transition-group標簽就可以了。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .fade-enter-active, .fade-leave-active { transition: opacity 1s; color: red; } .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0; } </style> </head> <body> <div id="app"> <transition-group name="fade"> <div v-for="item in list" key="item.id">{{item.title}}</div> </transition-group> <button @click="handleClick">增加</button> </div> <script src="js/vue.js"></script> <script> var count = 0 // 1. 創建Vue的實例 let vm = new Vue({ el:'#app', data:{ list:[] }, methods:{ handleClick:function(){ this.list.push({ id:count++, title:'hello kitty!' }) } } }); </script> </body> </html>
七、動畫封裝
我們可以將動畫以組件的方式進行封裝起來,以后需要使用這個動畫時,直接通過插槽將組件放入插槽即可。
例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <script src='js/velocity.min.js'></script> </head> <body> <div id="app"> <fade :show="show"> <div> hello div </div> </fade> <fade :show="show"> <h1>hello H1</h1> </fade> <button @click="handleClick">增加</button> </div> <script src="js/vue.js"></script> <script> Vue.component('fade',{ props:['show'], template:`<transition @before-enter="handleBeforeEnter" @enter="handleEnter"> <slot v-if="show"></slot> </transition>`, methods:{ handleBeforeEnter:function(el){ el.style.color="red" }, handleEnter:function(el,done){ setTimeout(()=>{ Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 }) Velocity(el, { fontSize: '1em' }, { complete: done }) done() },2000) } } }) // 1. 創建Vue的實例 let vm = new Vue({ el:'#app', data:{ show:false }, methods:{ handleClick:function(){ this.show=!this.show } } }); </script> </body> </html>
我們這里封裝了一個fade組件,通過transition封裝一個slot,里面可以支持N個內容。然后將動畫效果封裝到鈎子函數,然后在鈎子函數里面放入CSS效果。這樣,就將動畫效果完全封裝在一個組件中了,隨時隨地可以使用這個帶動畫的組件啦。
寫了這么多,其實就是開頭的四種方式:
- 在CSS過渡和動畫中自動應用class【默認為fade開頭,也可以自定義,不寫name時為v開頭】
- 可以配合使用第三方 CSS 動畫庫,如 Animate.css【自定義class的方式】
- 在過渡鈎子函數中使用 JavaScript 直接操作 DOM
- 可以配合使用第三方 JavaScript 動畫庫,如 Velocity.js