Vue動畫

概述

動畫分爲兩種:transitionanimationvue只是將其融入組件中去使用了。css

使用場景

  • v-ifv-show顯示隱藏組件時添加動畫
  • 組件切換實現頁面切換,添加過渡動畫,淡入淡出效果加強用戶體驗

transition組件

vue內置組件,用以包裹想要實現動畫效果的dom節點,且只能包裹單個元素。html

如何實現包裹多個元素?——須要給transition所包裹的子元素屬性標籤上添加v-ifv-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-activev-enter-to,隨着運動的進行,上述兩個class屬性逐漸消失。app

name屬性:transition標籤頭部可添加name屬性用以區分不一樣動畫。dom

<transition name="fade"></transition>
<!-- vue就會將 .v-enter 變爲 .fade-enter 用以私有化動畫樣式 -->
複製代碼

appear屬性:動畫一開始變展現出來。ide

<transition appear><transition>
複製代碼

type屬性:存在transitionanimation結合的動畫,而且二者的動畫時間存在長短的區別,咱們能夠再transition標籤頭部加上type熟悉,用於告訴vue咱們的動畫是以哪一種方式的時間爲基準的,避免上下竄動的不和諧效果,保持了兩個動畫的同步。函數

transition-group列表過渡

transition的區別:動畫

  • transition-group會生成一個真實的dom節點,默認爲span,經過tag="ul"可實現默認切換
  • transition-group必需要有key

pic

小栗子

.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; /* 離開時候脫離文檔流 */
}
複製代碼

栗子a: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')
        }
    }
})
複製代碼

栗子b: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)
        }
    }
})
複製代碼
相關文章
相關標籤/搜索