在 Vue.js 中使用 Velocity.js

Vue.js 是目前人气很高的前端框架之一, 看看 github 上的 star 就知道了,Vue 中除了css过渡动画,还可以实现 js动画,Velocity.js 就可以完美运用其中(官方例子

1. 使用 js钩子函数

在 Vue 中实现 js动画,一般会通过 Vue 提供的几个 js 钩子函数 搭配v-show指令来实现,钩子函数会在元素进场或离场状态时自动调用,下面列举了常用的6个钩子函数(函数名可自定义):

JavaScript
// ...
methods: {
  // --------
  // 进入中
  // --------
  // 在元素即将显示时
  beforeEnter: function (el) {
    // ...
  },
  // 在 beforeEnter 之后,元素运行进场动画时
  enter: function (el, done) {
    // 这里第二个参数 done 就是下面的 afterEnter 函数
    done()
  },
  // 元素进场动画 enter 结束时
  afterEnter: function (el) {
    // ...
  },
  // --------
  // 离开时
  // --------
  // 元素即将隐藏时
  beforeLeave: function (el) {
    // ...
  },
  // 在 beforeLeave 之后,元素运行离场动画时
  leave: function (el, done) {
    // 这里第二个参数 done 就是下面的 afterLeave 函数
    done()
  },
  // 元素离场动画 leave 结束时
  afterLeave: function (el) {
    // ...
  }
}

Vue 中具体使用 velocity.js 的示例:

HTML
<div id="app">
    <transition
        name="showRect"
        @before-enter="handleBeforeEnter"
        @enter="handleEnter"
        @after-enter="handleAfterEnter"
        @before-leave="handleBeforeLeave"
        @leave="handleLeave"
        @after-leave="handleAfterLeave"
        :css="false"
    >
        <div class="rect" v-show="show"></div>
    </transition>
    <button @click="handleClick">切换显示方块</button>
</div>
<script src="other/vue@2.5.16"></script>
<script src="http://cdn.jsdelivr.net/npm/velocity-animate@1.5.0/velocity.min.js"></script>

推荐对于仅使用 js过渡的 元素添加v-bind:css="false",Vue 会跳过 CSS 的检测,这也可以避免过渡过程中 CSS 的影响。

CSS
.rect {
    width: 50px;
    height: 50px;
    background: #4dd0e1;
}
JavaScript
var vm = new Vue({
    el: '#app',
    data: {
        // show状态决定方块是显示还是隐藏
        show: false
    },
    methods: {
        handleClick: function () {
            this.show = !this.show;
        },
        handleBeforeEnter: function (el) {
            el.style.opacity = 0;
            console.log('方块显示动画即将执行');
        },
        handleEnter: function (el, done) {
            Velocity(el, 'stop');
            Velocity(el, {
                backgroundColor: '#0085eb',
                opacity: 1,
                translateX: 260,
                rotateZ: ['360deg', 0]
            }, {
                duration: 1000,
                easing: [ 0.4, 0.01, 0.165, 0.99 ],
                complete: done
            });
            console.log('方块显示动画执行中...');
        },
        handleAfterEnter: function (el) {
            console.log('方块显示动画结束');
        },
        handleBeforeLeave: function (el) {
            console.log('方块隐藏动画即将执行');
        },
        handleLeave: function (el, done) {
            Velocity(el, 'stop');
            Velocity(el, {
                backgroundColor: '#4dd0e1',
                opacity: 0,
                translateX: 0,
                rotateZ: [0, '360deg']
            }, {
                duration: 1000,
                easing: [ 0.4, 0.01, 0.165, 0.99 ],
                complete: done
            });
            console.log('方块隐藏动画执行中...');
        },
        handleAfterLeave: function (el) {
            console.log('方块隐藏动画结束');
        }
    }
});

注意:当只用 js动画 过渡的时候,在enterleave钩子函数中,回调函数done是必须的,否则它们会被同步调用,动画会立即完成(直接跳转到结束状态)

2. 使用元素引用

ref被用来给元素或子组件注册引用信息。 引用信息将会注册在父组件的$refs对象上。如果在普通的 DOM 元素上使用, 引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例

对于一些复杂的多元素动画又不需要状态管理时,在元素上使用ref比较方便(推荐尽量使用第一种钩子函数方式,Vue 中不鼓励直接操作 dom)

修改下上面示例的代码,让方块做一个向右移动并旋转的动画:

HTML
<div id="app">
    <div class="rect" ref="rect"></div>
</div>

直接在动画元素上增加一个ref属性

JavaScript
var vm = new Vue({
    el: '#app',
    mounted: function() {
        Velocity(this.$refs.rect, {
            backgroundColor: '#0085eb',
            translateX: 260,
            rotateZ: '360deg'
        }, {
            duration: 1000,
            easing: [ 0.4, 0.01, 0.165, 0.99 ]
        });
    }
});

因为ref本身是作为渲染结果被创建的, 在初始渲染时获取不到它们,所以动画的代码必须放在 生命周期函数mounted中, 在 Vue 的实例挂载到 dom 时再执行)这里的this.$refs.rect就指向<div ref="rect">