Vue2.5学习笔记(三)动画

1.Vue中CSS动画原理

现有页面如下:
在这里插入图片描述
通过按钮可以控制文字的隐藏和显示。

现在的需求是:为文字的隐藏和显示添加渐隐渐现动画效果。
Vue 提供了 transition 的封装组件,将需要应用过渡效果的组件包裹在transition内:

        <transition>
            <h1 v-if="show">Hello,World!</h1>
        </transition>

在这里插入图片描述
动画原理:

        /* 渐显效果 */
        .v-enter{
            opacity:0;
        }
        .v-enter-active{
            transition : opacity 3s;
        }
        /* 渐隐效果 */
        .v-leave-to{
            opacity:0;
        }
        .v-leave-active{
            transition : opacity 3s;
        }

在这里插入图片描述
在这里插入图片描述

2.在Vue中使用animate.css库

我们可以使用关键帧动画来添加比较复杂的动画效果,示例如下:

    <style>
        @keyframes bounce-in{
            0%{
                transform: scale(0);
            }
            50%{
                transform: scale(1.5);
            }
            100%{
                transform: scale(1);
            }
        }
        .v-enter-active{
            transform-origin: left center;
            animation: bounce-in 1s;
        }
        
        .v-leave-active{
            transform-origin: left center;
            animation: bounce-in 1s reverse; 
        }
    </style>
    <div id="app">
        <transition>
            <h1 v-if="show">Hello,World!</h1>
        </transition>
        <button @click="handleClick">{{buttonText}}</button>
    </div>

我们知道,Vue是通过在动画的生命周期中动态地给DOM元素添加或删除相应的类名来实现动画的。
那么,像.v-enter-active、.v-leave-active能不能简化为自定义的类名呢?
答案是可以。
这样做:

        <transition
            enter-active-class="active"
            leave-active-class="leave"
        >

这样做就预示着我们可以使用第三方CSS动画库来完成动画效果,以animate.css库为例:

        <transition
            enter-active-class="animate__animated animate__rubberBand"
            leave-active-class="animate__animated animate__rubberBand"
        >

3.在Vue中同时使用过渡和动画

我们发现,在页面刷新时,设置了进入动画的元素在第一次出现时并不会有动画效果,为例让页面刷新时便出现动画,我们可以这样做:

        <transition
            appear
            enter-active-class="animate__animated animate__jello"
            leave-active-class="animate__animated animate__jello"
            appear-active-class="animate__animated animate__jello"
        >
            <h1 v-if="show">Hello,World!</h1>
        </transition>

同时在Vue中使用过渡和动画:

    <style>
        .fade-enter,
        .fade-leave-to{
            opacity: 0;
        }
        .fade-enter-active,
        .fade-leave-active{
            transition: opacity 3s;
        }
    </style>
        <transition
            name="fade"
            appear
            enter-active-class="animate__animated animate__jello fade-enter-active"
            leave-active-class="animate__animated animate__jello fade-leave-active"
            appear-active-class="animate__animated animate__jello"
        >
            <h1 v-if="show">Hello,World!</h1>
        </transition>

animate.css中,动画默认时长为1秒;
而我们自定义的过渡动画为3秒;
那么这两者放在一起的效果究竟以哪个为准?
我们可以在transition标签上使用type属性,来指定动画的时长以谁为准。

        <transition
            type="transition"
            name="fade"
            appear
            enter-active-class="animate__animated animate__jello fade-enter-active"
            leave-active-class="animate__animated animate__jello fade-leave-active"
            appear-active-class="animate__animated animate__jello"
        >
            <h1 v-if="show">Hello,World!</h1>
        </transition>

自定义动画执行总时长:使用transition标签的:duration属性

        <transition
            :duration="10000"
            name="fade"
            appear
            enter-active-class="animate__animated animate__jello fade-enter-active"
            leave-active-class="animate__animated animate__jello fade-leave-active"
            appear-active-class="animate__animated animate__jello"
        >
            <h1 v-if="show">Hello,World!</h1>
        </transition>

分别为入场和出场指定不同的动画时长::duration="{enter:5000,leave:1000}"

4.Vue中的JS动画与Velocity.js的结合

Vue提供了一些列js钩子

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"

  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>

使用钩子完成入场动画:

<body>
    <div id="app">
        <transition
            name="fade"
            @before-enter="handleBeforeEnter"
            @enter="handleEnter"
            @after-enter="handleAfterEnter"
        >
            <h1 v-if="show">Hello,World!</h1>
        </transition>
        <button @click="handleClick">{{buttonText}}</button>
    </div>
    <script>
        var vm = new Vue({
            el:"#app",
            data:{
                show:true,
                buttonText:"隐藏"
            },
            methods:{
                handleClick:function(){
                    this.show = !this.show;
                    if(this.buttonText === "隐藏"){
                        this.buttonText = "显示";
                    }else{
                        this.buttonText = "隐藏"
                    }
                },
                handleBeforeEnter:function(el){
                    el.style.color = 'red';
                },
                handleEnter:function(el,done){
                    setTimeout(() => {
                        el.style.color = 'green';
                        // 当动画执行结束后,必须手动调用done(),告诉Vue动画已经执行完毕
                    },2000);
                    setTimeout(() => {
                        done();
                    },4000);
                },
                handleAfterEnter:function(el){
                    el.style.color = '#000';
                }
            }
        })
    </script>
</body>

el参数是动画包裹的标签,通常是transiton标签内的内容。
当只用 JavaScript 过渡的时候,在 enterleave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。

为简化动画,我们使用Velocity.js库
下面用Velocity库实现渐显效果:

                handleEnter:function(el,done){
                   Velocity(el,{opacity:1},{duration:1000,complete:done});
                },

5.Vue中多个元素的过渡

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>多个元素过渡</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
        .v-enter,.v-leave-to{
            opacity: 0;
        }
        .v-enter-active,.v-leave-active{
            transition: opacity 1s;
        }
    </style>
</head>
<body>
    <div id="app">
        <transition mode="in-out">
            <h1 v-if="show" key="hello">Hello,World!</h1>
            <h1 v-else key="bye">Bye,World!</h1>
        </transition>
        <button @click="handleClick">{{buttonText}}</button>
    </div>
    <script>
        var vm = new Vue({
            el:"#app",
            data:{
                show:true,
                buttonText:"隐藏"
            },
            methods:{
                handleClick:function(){
                    this.show = !this.show;
                    if(this.buttonText === "隐藏"){
                        this.buttonText = "显示";
                    }else{
                        this.buttonText = "隐藏"
                    }
                }
            }
        })
    </script>
</body>
</html>

6.Vue中多个组件的过渡

以下代码通过v-if+transiton的形式实现组件切换的过渡:

<body>
    <div id="app">
        <transition mode="in-out">
            <child-one v-if="show" key="hello">Hello,World!</child-one>
            <child-one v-else key="bye">Bye,World!</child-one>
        </transition>
        <button @click="handleClick">{{buttonText}}</button>
    </div>
    <script>
        Vue.component('child-one',{
            template:'<div>child-one</div>'
        })

        Vue.component('child-two',{
            template:'<div>child-two</div>'
        })
        var vm = new Vue({
            el:"#app",
            data:{
                show:true,
                buttonText:"隐藏"
            },
            methods:{
                handleClick:function(){
                    this.show = !this.show;
                    if(this.buttonText === "隐藏"){
                        this.buttonText = "显示";
                    }else{
                        this.buttonText = "隐藏"
                    }
                }
            }
        })
    </script>
</body>

下面通过动态组件的形式来实现同样的效果:

        <transition mode="out-in">
            <component :is="type"></component>
        </transition>

通过动态切换type来实现。

7.Vue中的列表过渡

如果我们使用数据动态渲染列表项,在列表项增加或减少时我们想要动画效果,如何实现?
使用<transition-group>标签包裹需要过渡的列表
使用<transition-group>相当于为每个列表项添加一个<transiton>标签包裹

<style>
    .v-enter,.v-leave-to{
        opacity: 0;
    }
    .v-enter-active,.v-leave-active{
        transition: opacity 1s;
    }
</style>
<body>
    <div id="app">
        <transition-group>
            <div v-for="item in list" :key="item.id">{{item.content}}</div>
        </transition-group>
        <button @click="handleClick">add</button>
    </div>
    <script>
        var index = 0;
        var vm = new Vue({
            el:"#app",
            data:{
                list:[]
            },
            methods:{
                handleClick:function(){
                    this.list.push({
                        id:index++,
                        content:"Hello,world"
                    })
                }
            }
        })
    </script>
</body>

8.Vue中的动画封装

在Vue中,可以将动画封装进一个组件,这个组件的所有实例都会拥有同样的动画,非常方便。
如何封装?利用插槽。
封装方式一:

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>动画封装</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
        /* 渐显效果 */
        .v-enter{
            opacity:0;
        }
        .v-enter-active{
            transition : opacity 3s;
        }
        /* 渐隐效果 */
        .v-leave-to{
            opacity:0;
        }
        .v-leave-active{
            transition : opacity 1s;
        }
    </style>
</head>
<body>
    <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>
    <script>
        Vue.component('fade',{
            props:['show'],
            template:`
                <transition>
                    <slot v-if="show"></slot>
                </transition>
            `
        })
        var vm = new Vue({
            el:"#app",
            data:{
                show:false,
            },
            methods:{
                handleClick:function(){
                    this.show = !this.show;
                }
            }
        })
    </script>
</body>

像下面这样使用JS钩子定义动画,可以避免在style标签内定义css样式,可以完全将动画封装到组件内:

<body>
    <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>
    <script>
        Vue.component('fade',{
            props:['show'],
            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';
                    },1000);
                    setTimeout(() => {
                        done();
                    },2000);
                },
                handleAfterEnter:function(el){
                    el.style.color = "#000";
                }
            }
        })
        var vm = new Vue({
            el:"#app",
            data:{
                show:false,
            },
            methods:{
                handleClick:function(){
                    this.show = !this.show;
                }
            }
        })
    </script>
</body>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值