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