Vue入门4——动画

484 阅读2分钟

CSS动画及原理 过渡动画效果

  • transition包裹的标签能设置动画效果。vue会自动地在一些时间点上,向transition标签增加一些类名。

过渡的动画效果 通过C3中transition属性的形式实现

显示

image.png

  • transition包裹,vue自动分析元素CSS样式然后构建一个动画流程:
    动画被执行的一瞬间,往div上增加两个类名。
    动画运行到第二帧,删除一个增加一个。
    动画运行到结束的一瞬间。
  • opacity透明度,原始默认值为1。动画运行到第二帧,移除了fade-enter,则opacity变为1,而此时fade-enter-to监听到fade-enter-to发生变化,则让其在3s内完成变化。
  • transition起的名字是fade,所以样式表选择器前缀为fade,如果不起名字,默认为v

隐藏

image.png

代码

   .fade-enter,
   .fade-leave-to {
        opacity: 0;
    }
    .fade-enter-active,
    .fade-leave-active {
        transition: opacity 3s;
        /* 对opacity进行transition的监控,如果监控到opacity发生变化,会慢慢变化 */
    }
<body>
    <div id="root">
        <transition name="fade">
            <div v-if="show">hello world</div>   
        </transition>
        <button @click="handleClick">切换</button>
    </div>
    <script>
        var vm=new Vue({
            el:'#root',
            data:{
                show:true
            },
            methods: {
                handleClick: function(){
                    this.show=!this.show
                }
            }
        })
    </script>
</body>

keyframse形式的C3动画

    <style>
        /* 定义keyframes形式的C3叫做bounce-in的动画效果 */
        @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;
        }

选择器换个名字也可以,自己定义enter-activate-class的名字:

在Vue中使用Animate.css库

!DOCTYPE html>
<html lang="en"> 
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./vue.js"></script>
    <link rel="stylesheet" type="text/css" href="./animate.css">  
</head>
<body>
    <div id="root">
        <transition 
            name="fade"
            enter-active-class="animated swing"
            leave-active-class="animated shake"    
        >
        <!--自定义class名字 使用animated里的动画效果swing-->
        <!-- 使用animated库里的动画效果 -->
            <div v-show="show">hello world</div>
        </transition>
        <button @click="handleClick">切换</button>
    </div>
    <script>
        var vm=new Vue({
            el:'#root',
            data:{
                show:true
            },
            methods: {
                handleClick: function(){
                    this.show=!this.show
                }
            }
        })
    </script>
</body>
</html>

Vue中同时使用过渡和动画库

让hello world 第一次展示在页面上时也有动画→自定义一个类appear-active-class

<!DOCTYPE html>
<html lang="en"> 
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./vue.js"></script>
    <link rel="stylesheet" type="text/css" href="./animate.css">  
    <style>
        .fade-enter,
        .fade-leave-to {
            opacity: 0;
        }
        .fade-enter-active,
        .fade-leave-active {
            transition: opacity 5s;
        }
    </style>
</head>
<body>
    <div id="root">
        <transition 
             type="transition"duration="{enter:5000, leave:10000}"
            name="fade"
            appear
            enter-active-class="animated swing fade-enter-active"
            leave-active-class="animated shake fade-leave-active"  
            appear-active-class="animated swing"  
        >
        <!-- type动画时长以transition为准 -->
        <!-- 使用animated库里的动画效果 -->
            <div v-show="show">hello world</div>
        </transition>
        <button @click="handleClick">切换</button>
    </div>
    <script>
        var vm=new Vue({
            el:'#root',
            data:{
                show:true
            },
            methods: {
                handleClick: function(){
                    this.show=!this.show
                }
            }
        })
    </script>
</body>
</html>

image.png

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

通过Vue提供的钩子写JS动画

  • 不仅CSS可以实现动画,JS也可以,VUE提供了很多JS动画的钩子。

  • before-enter会自动接受参数el,即为transition包裹的标签。

  • enter接受两个参数,done为回调函数,当动画执行结束要调用一下回调函数,相当于告诉vue,动画已经执行完了。然后vue就会自动触发一个事件:

  • after-enter

  • 出场动画和入场动画类似,把enter换成leave。

    image.png image.png

引入Velocity动画库

shouce.jb51.net/velocity/in…

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="./vue.js"></script>
    <script src="./velocity.js"></script>
    <title>Document</title>
</head>

<body>
    <div id="root">
        <transition name="fade" @before-enter="handleBeforeEnter" @enter="handleEnter" @after-enter="handleAfterEnter">
            <div v-show="show">Hello World</div>
        </transition>
        <button @click="handleClick">toggle</button>
    </div>
    <script>
        var vm = new Vue({
            el: "#root",
            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) {
                    console.log('over');
                }
            },
        })
    </script>
</body>
</html>

Vue中多个元素或组件的过渡动画

元素之间的过渡动画

  • vue切换两个元素的时候,会尽量的复用DOM,要给两个div不同的key值,才不会自动复用DOM。
  • transition的属性mode设置元素切换的效果。
    in-out先显示 再隐藏
    out-in先隐藏 再显示
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="./vue.js"></script>
    <title>Document</title>
    <style>
        .v-enter,
        .v-leave-to {
            opacity: 0;
        }
        .v-enter-active,
        .v-leave-active{
            transition: opacity 1s;
        }
    </style>
</head>

<body>
    <div id="root">
        <transition mode="out-in">
            <div v-if="show" key="Hello">Hello World</div>
            <div v-else key="bye">Bye World</div>
        </transition>
        <button @click="handleClick">toggle</button>
    </div>
    <script>
        var vm = new Vue({
            el: "#root",
            data: {
                show: true
            },
            methods: {
                handleClick: function () {
                    this.show = !this.show
                }
            }
        })
    </script>
</body>
</html>

组件之间的过渡动画——动态组件

动态组件通过标签component定义,属性is让组件和对应的组件名绑定。

<body>
    <div id="root">
        <transition mode="out-in">
            <component :is="type"></component>
        </transition>
        <button @click="handleClick">toggle</button>
    </div>
    <script>
        Vue.component('child', {
            template: '<div>child</div>'
        })
        Vue.component('child-one', {
            template: '<div>child-one</div>'
        })
        var vm = new Vue({
            el: "#root",
            data: {
                type: 'child'
            },
            methods: {
                handleClick: function () {
                    this.type = this.type === 'child' ? 'child-one' : 'child';
                }
            }
        })
    </script>
</body>

Vue中的列表过渡

  • 尽量不要使用index作为key值

  • transition-group标签

  • div列表循环过后会变成几个div,里边都是hello world,在最外层加了一个transition-group,相当于在每个div标签外加了一个transition。把列表的过渡转化为单个元素的过渡,Vue动态找到时间点,增加一些class的名字。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="../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="root">
            <transition-group>
                <div v-for="item of list" :key="item.id">
                    {{item.title}}
                </div>
            </transition-group>
            <button @click="handleBtnClick">Add</button>
        </div>
        <script>
            var count = 0;
            var vm = new Vue({
                el: "#root",
                data: {
                    list: []
                },
                methods: {
                    handleBtnClick: function () {
                        this.list.push({
                            id: count++,
                            title: 'hello world'
                        })
                    }
                }
            })
        </script>
    </body>
    </html>
    

Vue中的动画封装

如何进行动画封装,让动画变得可复用。

封装一个组件,利用插槽

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <script src="../vue.js"></script>
   <title>Document</title>
   <style>
       .fade-enter,
       .fade-leave-to {
           opacity: 0;
       }
       .fade-enter-active,
       .fade-leave-active {
           transition: opacity 1s;
       }
   </style>
</head>
<body>
   <div id="root">
       <fade :show="show">
           <!-- 插槽 -->
           <div>Hello World</div> 
       </fade>

       <fade :show="show">
           <!-- 插槽 -->
           <div>Hi</div> 
       </fade>
       <button @click="handleClick">toggle</button>
   </div>
   <script>
       // 封装一个组件
       Vue.component('fade',{
           props:['show'],
           template:
           `
           <transition name="fade">
               <slot v-if="show"></slot>
           </transition>
           `
       }) 
       var vm = new Vue({
           el: "#root",
           data: {
               show: false
           },
           methods: {
               handleClick: function () {
                   this.show = !this.show
               }
           },
       })
   </script>
</body>

</html>

把动画样式也封装了,用JS写动画

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="../vue.js"></script>
    <title>Document</title>
</head>
<body>
    <div id="root">
        <fade :show="show">
            <!-- 插槽 -->
            <div>Hello World</div> 
        </fade>
        <fade :show="show">
            <!-- 插槽 -->
            <div>Hi</div> 
        </fade>
        <button @click="handleClick">toggle</button>
    </div>
    <script>
        // 封装一个组件 动画通过JS来写 完整把所有动画实现封装到一个组件里边
        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(()=>{
                        el.style.color = 'green'
                        done();//动画执行完了要调用done函数
                    },2000)
                    
                }
            }
        }) 
        var vm = new Vue({
            el: "#root",
            data: {
                show: false
            },
            methods: {
                handleClick: function () {
                    this.show = !this.show
                }
            }
        })
    </script>
</body>
</html>

动态过渡、状态过渡...... 见Vue官网文档