動畫分爲兩種:transition
和animation
,vue
只是將其融入組件中去使用了。css
v-if
、v-show
顯示隱藏組件時添加動畫transition
組件vue
內置組件,用以包裹想要實現動畫效果的dom
節點,且只能包裹單個元素。html
如何實現包裹多個元素?——須要給transition
所包裹的子元素屬性標籤上添加v-if
、v-else
,須要注意的是:當transition
所包裹子元素的標籤名相同時,須要給其添加上key
值,以避免影響dom
工做。vue
transition
實現原理給當前須要呈現變化的dom
元素添加上可能的6個class
樣式:markdown
v-enter
v-enter-active
v-enter-to
過程:vue
自動幫咱們添加切換了樣式,咱們只需設置好切換的類別便可。在dom
元素運動前一幀給其綁定一個class
屬性v-enter
,隨即消失。來到運動過程前一刻給其class
屬性變爲v-enter-active
和v-enter-to
,隨着運動的進行,上述兩個class
屬性逐漸消失。app
name
屬性:transition
標籤頭部可添加name
屬性用以區分不一樣動畫。dom
<transition name="fade"></transition> <!-- vue就會將 .v-enter 變爲 .fade-enter 用以私有化動畫樣式 --> 複製代碼
appear
屬性:動畫一開始變展現出來。ide
<transition appear><transition> 複製代碼
type
屬性:存在transition
和animation
結合的動畫,而且二者的動畫時間存在長短的區別,咱們能夠再transition
標籤頭部加上type
熟悉,用於告訴vue
咱們的動畫是以哪一種方式的時間爲基準的,避免上下竄動的不和諧效果,保持了兩個動畫的同步。函數
transition-group
列表過渡與transition
的區別:動畫
transition-group
會生成一個真實的dom
節點,默認爲span
,經過tag="ul"
可實現默認切換transition-group
必需要有key
值.v-enter, /* 時間點,開始動畫以前元素的起始狀態 */ .v-leave-to{ /* 時間點,元素完成動畫離開的終止狀態 */ opacity: 0; transform: translateX(70px) } .v-enter-active, /* 入場動畫時間段 */ .v-leave-active{ /* 離場動畫時間段 */ transition: all 0.8s ease; } .private-enter, .private-leave-to{ opacity: 0; transform: translateY(70px) } .private-enter-active, .private-leave-active{ transition: all 0.9s ease; } 複製代碼
<div id="app"> <transition> <h1 v-show="flag1">使用過渡類名實現動畫效果</h1> </transition> <br> <transition name="private"> <h1 v-show="flag2">demo</h1> </transition> <input type="button" value="按鈕1" @click="flag1 = !flag1"> <input type="button" value="按鈕2" @click="flag2 = !flag2"> </div> 複製代碼
const app = new Vue({ el: '#app', data: { flag1: true, flag2: true } }) 複製代碼
在使用第三方庫(如:animate.css
)的時候,使用此方式比較多,常應用於退場動畫中。this
animate.css
基於animation
來寫的,其@keyframe
中已經設置了初始值和結束值,因此咱們只須要設置一下運動過程便可。譬以下面leave-active-class="animate shake"
中的屬性值animate
是必須的,後面的shake
動畫樣式可去官網中尋找。
.a{ opacity: 0; } .b{ transition: opacity 10s; } .c{ opacity: 1; } 複製代碼
<div id="app"> <transition enter-class="a" enter-active-class="b" enter-to-class="c" appear leave-active-class="animated shake"> <h1 v-show="flag">我要運動</h1> </transition> <button @click="flag = !flag">change</button> </div> 複製代碼
const app = new Vue({ el: '#app', data: { flag: true } }) 複製代碼
animate.css
的其餘使用:
<div id="app"> <transition enter-active-class="bounceIn" leave-active-class="bounceOut"> <h3 v-if="flag">11111111111</h3> </transition> <input type="button" value="toggle1" @click="flag=!flag"> <!-- 設置入場和離場的動畫時長 --> <transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="1000"> <h3 v-if="flag1" class="animated">222222222222</h3> </transition> <input type="button" value="toggle2" @click="flag1=!flag1"> <!-- 分別設置入場和離場的動畫時長 --> <transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="{enter: 100,leave: 1000}"> <h3 v-if="flag2" class="animated">333333333333</h3> </transition> <input type="button" value="toggle3" @click="flag2=!flag2"> </div> 複製代碼
js
鉤子函數實現動畫@before-enter
@enter
@after-enter
@enter-cancelled
@before-leave
@leave
@after-leave
@leave-cancelled
.fade-enter{ /* 定義進入過渡的開始狀態,元素插入以前生效,元素插入的下一幀移除 */ opacity: 0; } .fade-enter-active{ /* 定義進入過渡生效時的動畫狀態 */ transition: opacity 1s; } .fade-enter-to{ /* 定義進入過渡的結束狀態,過渡動畫完成以後移除 */ opacity: 1; } .fade-leave{ opacity: 1; } .fade-leave-active{ transition: opacity 1s; } .fade-leave-to{ opacity: 0; } /* ------------分割線---------- */ .slide-enter{ opacity: 0; transform: translateY(20px); } .slide-enter-active{ transition: opacity 1s; /* transition和animation結合使用 */ animation: slide-in 1s ease-out; } .slide-enter-to{ opacity: 1; transform: translateY(0px); } .slide-leave{ opacity: 1; transform: translateY(0px); } .slide-leave-active{ transition: opacity 1s; animation: slide-out 1s ease-out; position: absolute; } .slide-leave-to{ opacity: 0; transform: translateY(20px); } .slide-mode{ transition: transform 1s; } @keyframes slide-in{ from{ transform: translateY(20px); } to{ transform: translateY(0px); } } @keyframes slide-out{ from{ transform: translateY(0px); } to{ transform: translateY(20px); } } /* ---------分割線------- */ .a{ opacity: 0; } .b{ transition: opacity 10s; } .c{ opacity: 1; } 複製代碼
<div id="app"> <!-- 1 --> <button @click="show=!show">點擊</button> <br> <select v-model="animatedName"> <option value="fade">閃現過渡動畫</option> <option value="slide">上下滑動過渡動畫</option> </select> <transition :name="animatedName"> <div v-show="show">我是屬性綁定選擇樣式</div> </transition> <!-- 2 --> <br> <transition name="fade" appear> <div v-show="show">我是私有化提示語</div> </transition> <transition name="slide" appear> <div v-show="show">我是一句提示語</div> </transition> <!-- 3 --> <transition name="slide" appear mode="out-in"> <div v-if="show">sxw</div> <p v-else>iu</p> </transition> <!-- 4 --> <transition enter-class="a" enter-active-class="b" enter-to-class="c" appear> <div v-show="show">自定義樣式標籤</div> </transition> <!-- 5 --> <transition enter-active-class="animated bounce" leave-active-class="animated shake" appear> <div v-show="show">引用第三方庫</div> </transition> </div> 複製代碼
加強用戶體驗,以上栗子的兩個注意點:
.slide-mode{ transition: transform 1s; } 複製代碼
.slide-leave-active{ transition: opacity 1s; animation: slide-out 1s ease-out; position: absolute; /* 離開時候脫離文檔流 */ } 複製代碼
js
鉤子函數實現動畫<button @click="load = !load">js實現動畫</button> <br> <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"> <!-- 上一行代碼告訴vue咱們不是使用css去實現動畫的,減小了vue一開始去找css的步驟 --> <div v-if="load" style="width: 100px;height: 100px;background-color: red"></div> </transition> 複製代碼
const vm = new Vue({ el: '#app', data: { load: false, divWidth: '' }, methods: { beforeEnter(el) { console.log(el) // <div v-if="load" style="width: 100px;height: 100px;background-color: red"></div> console.log("beforeEnter") this.divWidth = 10 // 限定每次初始動畫時的div寬度 el.style.width = this.divWidth + 'px' }, enter(el, done) { console.log('enter') done(); // 這裏須要執行一下done函數才能往下運行其餘鉤子函數 let round = 1; const timer = setInterval(() => { el.style.width = (this.divWidth + round * 10) + 'px' round ++ if(round > 20) { clearInterval(timer) done() } }, 20) }, afterEnter(el) { console.log('afterEnter') el.style.width = '300px' }, enterCancelled(el) { console.log('enterCancelled') }, beforeLeave(el) { console.log('beforeLeave') this.divWidth = '300' el.style.width = this.divWidth + 'px' }, leave(el, done) { console.log('leave') let round = 1 const timer = setInterval(() => { el.style.width = (this.divWidth - round * 10) + 'px' round ++ if(round > 20) { clearInterval(timer) done() } }, 20) }, afterLeave(el) { console.log('afterLeave') }, leaveCancelled(el) { console.log('leaveCancelled') } } }) 複製代碼
js
鉤子函數實現動畫<div id="app"> <button @click="addClick">添加列表</button> <transition-group tag="ul" name="slide"> <li v-for="(list,index) in lists" @click="removeClick(index)" :key="list"> {{ list }} </li> </transition-group> </div> 複製代碼
const vm = new Vue({ el: '#app', data: { list: [1,2,3] }, methods: { addClick() { const position = Math.floor(Math.random() * this.list.length) // 生成隨機數 this.list.splice(position, 0, this.list.length + 1) // 添加的位置 刪除的元素 添加元素個數 }, removeClick(index) { this.list.splice(index, 1) } } }) 複製代碼
demo
- 小球加入購物車動畫實現<div id="app"> <input type="button" value="加入購物車" @click="flag=!flag"> <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter"> <div class="ball" v-show="flag" style="width: 15px;height: 15px;background-color: red;border-radius: 50%;"></div> </transition> </div> 複製代碼
const app = new Vue({ el: '#app', data: { flag: false }, methods: { // el表示要執行動畫的dom元素 beforeEnter(el) { // 動畫入場前,設置元素開始動畫的起始位置 el.style.transform = 'translate(0, 0)' }, enter(el, done) { // 設置小球完成動畫以後的結束狀態 el.offsetWidth // 強制刷新動畫 el.style.transform = 'translate(150px, 450px)' el.style.transition = 'all 1s ease' // 執行done函數,完成下面鉤子函數 done() }, afterEnter(el) { // 動畫完成以後調用afterEnter函數 // 控制小球的顯示與隱藏,直接跳事後半場動畫,讓flag標識符變爲false this.flag = !this.flag el.style.opacity = 0.5 } } }) 複製代碼
demo
- 列表動畫 - 添加刪除功能li{ border: 1px dashed #999; margin: 5px; line-height: 35px; padding-left: 5px; font-size: 12px; width: 100%; } li:hover{ background-color: hotpink; transition: all 0.8s ease; } .v-enter, .v-leave-to{ opacity: 0; transform: translateY(80px); } .v-enter-active, .v-leave-active{ transition: all 0.6s ease; } /* 列表的排序過渡,不只可以設置進場和離場動畫,還能夠改變定位 */ /* 改變定位須要設置v-move屬性,他會在元素改變定位的過程當中應用 */ /* v-move和v-leave-active結合使用,使得列表的過渡動畫更加平緩柔和! */ .v-move{ transition: all 0.8s ease; } .v-leave-active{ position: absolute; } 複製代碼
<div id="app"> <div> <label for=""> Id: <input type="text" v-model="id"> </label> <label for=""> Name: <input type="text" v-model="name"> </label> <input type="button" value="添加" @click="add"> </div> <ul> <!-- 列表過渡,若是須要過渡的元素是經過v-for循環渲染出來的,就不能使用transition包裹,應該使用transitionGroup --> <!-- 若要爲v-for循環建立的元素設置動畫,必須爲每一個元素綁定key值 --> <!-- appear屬性實現頁面展現時的入場動畫 --> <transition-group appear tag="ul"> <li v-for="(item,index) in list" :key="item + index" @click="del(index)"> {{item.id}} -- {{item.name}} </li> </transition-group> </ul> </div> 複製代碼
const vm = new Vue({ el: '#app', data: { id: '', name: '', list: [ { id: 1, name: 'a' }, { id: 2, name: 'b' }, { id: 3, name: 'c' } ] }, methods: { add() { this.list.push( {id: this.id,name: this.name }) this.id = this.name = '' }, del(index) { this.list.splice(index, 1) } } }) 複製代碼