Effect

CodePen 地址

前端使用 SPA 之后,能获得更多的控制权,比如页面切换动画,使用后端页面我们可能做不了上面的效果,或者做出来会出现明显的闪屏。因为所有资源都需要重新加载。

今天使用 vue,vue-router,animejs 来讲解如何上面的效果是如何实现的。

步骤

  1. 点击菜单,生成 Bubble,开始执行入场动画
  2. 页面跳转
  3. 执行退场动画

函数式调用组件

我希望效果是通过一个对象去调用,而不是 v-show, v-if 之类的指令,并且为了保持统一,仍然使用 Vue 来写组件。我通常会用新的 Vue 根节点来实现,让效果独立于业务组件之外。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let instance = null

function createServices (Comp) {
// ...
return new Vue({
// ...
}).$children[0]
}

function getInstance () {
instance = instance || createServices(BubbleTransitionComponent)
return instance
}

const BubbleTransition = {
scaleIn: () => {
return getInstance().animate('scaleIn')
},
fadeOut: () => {
return getInstance().animate('fadeOut')
}
}

接着实现 BubbleTransitionComponent,那么 BubbleTransition.scaleIn, BubbleTransition.scaleOut 就能正常工作了。 这里使用 animejs 来做动画,animejs 是个轻量强大的动画库,用起来不需要多少成本。

这里使用 anime({}).finished 获得 Promise 对象,得到动画执行结束的回调。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<template>
<div class="transition-bubble">
<span v-show="animating" class="bubble" id="bubble">
</span>
</div>
</template>

<script>
import anime from 'animejs'
export default {
name: 'transition-bubble',
data () {
return {
animating: false,
animeObjs: []
}
},
methods: {
scaleIn (selector = '#bubble', {duration = 800, easing = 'linear'} = {}) {
// this.animeObjs.push(anime().finished)
},
fadeOut (selector = '#bubble', {duration = 300, easing = 'linear'} = {}) {
// ...
},
resetAnimeObjs () {
this.animeObjs.reset()
this.animeObjs = []
},
animate (action, thenReset) {
return this[action]().then(() => {
this.resetAnimeObjs()
})
}
}
}

最初的想法是,在 router config 里面给特定路由 meta 添加标记,beforeEach 的时候判断判断该标记执行动画。但是这种做法不够灵活,改成通过 Hash 来标记,结合 Vue-router,切换时重置 hash。

1
<router-link class="router-link" to="/#__bubble__transition__">Home</router-link>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

const BUBBLE_TRANSITION_IDENTIFIER = '__bubble__transition__'

router.beforeEach((to, from, next) => {
if (to.hash.indexOf(BUBBLE_TRANSITION_IDENTIFIER) > 0) {
const redirectTo = Object.assign({}, to)
redirectTo.hash = ''
BubbleTransition.scaleIn()
.then(() => next(redirectTo))
} else {
next()
}
})

router.afterEach((to, from) => {
BubbleTransition.fadeOut()
})

酷炫的动画能在一瞬间抓住用户的眼球,我自己也经常在逛一些网站的时候发出,wocao,太酷了!!!的感叹。可能最终的实现用不了几行代码,自己多动手实现一下,下次设计师提出不合理的动画需求时可以装逼,这种效果我分分钟能做出来,但是我认为这里不应该使用 ** 动画,不符合用户的心理预期啊。

CodePen 地址,欢迎 star

如需转载,请注明出处: http://w3ctrain.com / 2018/04/07/vue-page-bubble-transition/

helkyle

我叫周晓楷

我现在是一名前端开发工程师,在编程的路上我还是个菜鸟,w3ctrain 是我用来记录学习和成长的地方。