Vue Router 过渡动效
最近在做 H5 PWA 项目,技术栈是 Vue。
由于是 PWA 项目,所以应用的体验要无限往原生靠近,网页的过渡是很生硬的,没有任何的动效可言,很出戏,网页的感觉太强了,所以就想着给网页加上一些过渡动效。
翻阅了一下 Vue Router 的文档,提供了类似的案例。
如何实现
按照上述文档的案例,我们可以用 Vue 提供的 <transition>
搭配 <router-view>
来实现过渡动效。
1<router-view v-slot="{ Component }">
2 <transition name="fade" mode="out-in">
3 <component :is="Component" :key="route.path"></component>
4 </transition>
5</router-view>
1/* fade */
2.fade-enter-active,
3.fade-leave-active {
4 transition: opacity 0.5s ease;
5}
6
7.fade-enter-from,
8r .fade-leave-to {
9 opacity: 0;
10}
再进行路由跳转的时候已经可以看到过渡效果了:
但这个效果不是我们想要的,我们需要的是类似 iOS 页面栈的效果,所以还需要改造下动画:
1<router-view v-slot="{ Component }">
2 <transition name="slide-left">
3 <component :is="Component" :key="route.path"></component>
4 </transition>
5</router-view>
1/* slide */
2.slide-left-enter-active,
3.slide-left-leave-active {
4 transition: transform 300ms ease, opacity 400ms step-end;
5 backface-visibility: hidden;
6 width: 100vw;
7 height: 100vh;
8}
9
10.slide-left-enter-active {
11 position: fixed;
12 top: 0;
13 left: 0;
14 z-index: 1;
15}
16
17.slide-left-enter-active {
18 background-color: #fff;
19}
20
21.slide-left-enter-from {
22 transform: translateX(80vw);
23}
试下效果:
已经可以看到初步的效果了,还有一个细节需要处理,就是没办法区分前进和返回,我们需要自定义动画。
这里需要用到 Vue Router 提供的beforeEach
和afterEach
两个钩子函数:
1// 记录当前网页历史的位置
2let position = 0
3
4router.beforeEach((to) => {
5 // 判断是前进还是返回
6 const isBack = position > window.history.state.position
7 to.meta.transition = isBack ? "slide-right" : "slide-left"
8})
9
10router.afterEach(() => {
11 // 跳转后清空
12 position = window.history.state?.position || 0
13})
动态设置当前过渡动画:
1<router-view v-slot="{ Component, route }">
2 <transition :name="route.meta.transition">
3 <component :is="Component" :key="route.path"></component>
4 </transition>
5</router-view>
补充slide-right
动画样式:
1/* slide */
2.slide-left-enter-active,
3.slide-left-leave-active,
4.slide-right-enter-active,
5.slide-right-leave-active {
6 transition: transform 300ms ease, opacity 400ms step-end;
7 backface-visibility: hidden;
8 width: 100vw;
9 height: 100vh;
10}
11
12.slide-left-enter-active,
13.slide-right-enter-active,
14.slide-right-leave-active {
15 position: fixed;
16 top: 0;
17 left: 0;
18 z-index: 1;
19}
20
21.slide-right-leave-active {
22 z-index: 1;
23}
24
25.slide-left-enter-active {
26 background-color: #fff;
27}
28
29.slide-left-enter-from {
30 transform: translateX(80vw);
31}
32
33.slide-right-enter-from {
34 transform: translateX(-10vw);
35}
36
37.slide-right-leave-from {
38 transform: translateX(40vw);
39}
40
41.slide-right-leave-active {
42 transform: translateX(100vw);
43}
最终效果:
更多
有的路由或者场景可能不需要动画,一样可以通过上述beforeEach
钩子的指定某些路由动画效果为none
。
1router.beforeEach((to) => {
2 // 过滤某些页面的动画效果
3 if (to.path === "/no-transition") {
4 to.meta.transition = "none"
5 } else {
6 const isBack = position > window.history.state.position
7 to.meta.transition = isBack ? "slide-right" : "slide-left"
8 }
9})
可能遇到的问题
iOS 手势返回闪屏
在 iOS Safari 上使用手势返回时,如果动画效果是none
,有概率会闪现一帧上一个页面的内容,猜测是因为Transition
组件识别到css
中不存在的动画时会有一些边缘情况。
通过设置过渡效果none
的样式即可修复:
1.none-leave-from,
2.none-leave-active,
3.none-leave-to {
4 display: none;
5}
过渡效果可以自定义,这里只是一个简单的实现,可以根据自己的需求来调整。
希望这篇文章能帮助你更好地理解和使用Vue
和Vue Router
的过渡动效。如果你在实践中遇到任何问题,或者有任何建议,欢迎在评论区留言。
感谢你的阅读,期待下次再见。