vue动画

242 阅读1分钟

原生动画

在Vue中实现动画,与原生中实现是没有任何区别的
    使用js自己实现
    用css实现
    用第三库实现       

js动画

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: red;
        }
        .box2 {
            width: 200px;
            height: 200px;
        }
    </style>
</head>
<body>
    
    <div id="app">
        <button @click="animate">按钮</button>
        <div class="box" ref="box"></div>
    </div>

    <script src="./js/vue.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script>
        /**
         *  js
         */
        // let app = new Vue({
        //     el: '#app',
        //     methods: {
        //         animate() {
        //             // console.log( $(this.$refs.box) );  jq对象

        //             $(this.$refs.box).animate({
        //                 width: 200,
        //                 height: 200
        //             }, function() {
        //                 console.log('动画完成');
        //             })
        //         }
        //     }
        // });

    </script>
</body>
</html>

css动画

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>        
        .box {
            width: 100px;
            height: 100px;
            background-color: red;
            transition: all 1s;  
            /* 所有样式发生改变,触发动画 */
        }
        .box2 {
            
            width: 200px;
            height: 200px;
        }
    </style>
</head>
<body>
    
    <div id="app">
        <button @click="animate">按钮</button>
        /* <div class="box" ref="box"></div> */
        <hr />

        <div class="box" :class="{box2: animated}"></div>
    </div>

    <script src="./js/vue.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script>
        let app = new Vue({
            el: '#app',
            data: {
                animated: false
            },
            methods: {
                animate() {
                    // $(this.$refs.box).addClass('box2');

                    this.animated = !this.animated;
                }
            }
        });
    </script>
</body>
</html>

vue动画

自己实现的vue动画

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: red;
            /* transition: all 1s; */
        }
        .box2 {
            width: 200px;
            height: 200px;
        }
    </style>
</head>
<body>
    
    <div id="app">
        <button @click="animate">按钮</button>
        <div class="box" v-if="isShow" ref="box"></div>
    </div>

    <script src="./js/vue.js"></script>
    <script>
        /**
            transition  组件
            Vue 为我们在使用过程以下几个特殊情况提供一套动画模式
                - 条件渲染 (使用 `v-if`)
                - 条件展示 (使用 `v-show`)
                - 动态组件
                - 组件根节点
        */


        let app = new Vue({
            el: '#app',
            data: {
                isShow: false
            },
            methods: {
                animate() {
                    this.isShow = !this.isShow;
                    
                    // 1. 报错 this.$refs.box 为undefined
				    console.log(this.$refs.box)
                    this.$refs.box.classList.add('box2');
                    
                    // 2. 不报错 但没动画效果
                    // 渲染的过程也有一个异步的过程
                    // this.$nextTick(() => {
                    //    this.$refs.box.classList.add('box2');
                    // });
                    
                    // 3. 正常
                    // this.$nextTick(() => {
                    //     setTimeout(() => {
                    //         this.$refs.box.classList.add('box2');
                    //     }, 0);
                    // });
                }
            }
        });


		// 解析3的原因
        // let box1 = document.createElement('div');
        
        // 1.无效果
        // box1.classList.add('box2');
        // document.body.appendChild( box1 );
        
        // 2.无效果
        // 页面渲染的一瞬间,就已经存在box2了
        // box1.classList.add('box2');
        // ------------------------------------------------------------
        // 以上代码为宏任务,执行完后去渲染,完了再执行定时器里的东西

		// 3. 正常
        // 根据上面代码的结果再一次性的去渲染页面
        // 渲染丢到下一组任务中去
        // 定时器 下一轮的宏任务中执行
        // setTimeout(() => {
        //     box1.classList.add('box2');
        // }, 0);
    </script>
</body>
</html>

vue动画 - trasition

/**
    transition  组件
    Vue 为我们在使用过程以下几个特殊情况提供一套动画模式
        - 条件渲染 (使用 `v-if`)
        - 条件展示 (使用 `v-show`)
        - 动态组件
        - 组件根节点
*/
栗子
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: red;
            /* transition: all 1s; */
        }
        .box2 {
            width: 200px;
            height: 200px;
        }

        /* 运动周期中一直存在 */
        .slide-fade-enter-active, .slide-fade-leave-active {
            transition: all 1s ease;
        }

        /* 初始化的时候存在 */
        .slide-fade-enter {
            width: 0;
            height: 0;
        }

        /* 运动周期中一直存在 */
        .slide-fade-enter-to {
            width: 100px;
            height: 100px;
        }

        /* 离开的起点和进入的终点一直,可以合并 */
        .slide-fade-leave {
          	/*可以和slide-fade-enter-to合并*/
            width: 100px;
            height: 100px;
        }
        .slide-fade-leave-to {
          	/*可以和slide-fade-enter合并*/
            width: 0;
            height: 0;
        }
        
    </style>
</head>
<body>
    
    <div id="app">
        <button @click="animate">按钮</button>
        <!-- 找以 slide-fade 为前缀的样式 -->
        <transition name="slide-fade">
            <div class="box" v-if="isShow" ref="box"></div>
        </transition>
    </div>

    <script src="./js/vue.js"></script>
    <script>
        let app = new Vue({
            el: '#app',
            data: {
                isShow: false
            },
            methods: {
                animate() {
                    this.isShow = !this.isShow;
                    
                    // vue 解决了这个问题
                    // this.$nextTick(() => {
                    //     setTimeout(() => {
                    //         this.$refs.box.classList.add('box2');
                    //     }, 0);
                    // });
                }
            }
        });
    </script>
</body>
</html>

生命周期钩子函数

Vue 会在动画开始到结束的不同阶段中触发对应的一些钩子(事件)。

<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>
// ...
methods: {
  // --------
  // 进入中
  // --------

  beforeEnter: function (el) {
    // ...
  },
  // 当与 CSS 结合使用时
  // 回调函数 done 是可选的
  enter: function (el, done) {
    // ...
    done()
  },
  afterEnter: function (el) {
    // ...
  },
  enterCancelled: function (el) {
    // ...
  },

  // --------
  // 离开时
  // --------

  beforeLeave: function (el) {
    // ...
  },
  // 当与 CSS 结合使用时, 回调函数 done 是可选的,会自动监听transitionend
  // 如果不是css动画 手动done
  
  leave: function (el, done) {
    // ...
    done()
  },
  afterLeave: function (el) {
    // ...
  },
  // leaveCancelled 只用于 v-show 中
  leaveCancelled: function (el) {
    // ...
  }
}

当与 CSS 结合使用时, 回调函数 done 是可选的,会自动监听transitionend。当只用 JavaScript 过渡的时候,enterleave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。

插件

如果一个三方库需要对Vue进行扩展,不推荐直接全局这么写, Vue 提供了一个规范化的接口去对其进行扩展

/ 1. 导出一个函数 执行
// export default function(_Vue, options) {

// }

// 2. 导出一个对象,对象下必须有一个install, install方法会执行
// export default {
//     install(_Vue, options) {

        // _Vue.prototype.getData = function() {
        //     console.log('getData 获取数据');
        // }

//     }
// }

// 3. 导出一个class 还是会转成函数
export default class KKB {
    
    static f(_Vue, options) {
        _Vue.prototype.getData = function() {
            console.log('getData 获取数据');
        }
    }

    install(_Vue, options) {
        _Vue.prototype.getData = function() {
            console.log('getData 获取数据');
        }
    }

}
// Vue.use( KKB.f, {
//     a: 1
// } );

Vue.use( new KKB, {
    a: 1
} );