动手实现H5仿原生app前进后退切换效果
前言
最近在优化H5页面,我注意到当开发完成的移动端H5页面嵌入到微信小程序或者原生app中时,当触发页面路由切换会与原生app看上去有点格格不入,因为H5页面<router-view>
切换路由时是直接替换了原来页面的内容,在视觉效果上看到的是页面的跳转变化都是在同一个页面上,并没有一级二级页面这种视觉差,因此,参考了原生app中的页面切换效果,我打算将已经成熟的H5项目改造一下,优化视觉上的体验效果。 话不多说,先上效果:
实现思路
在观察原生APP页面切换时不难发现,其实就两个效果,在路由前进时旧的页面需要从中心往左平移直至隐藏,新的页面则需要右边隐藏状态平移到屏幕中央。在页面返回到时候做相反的操作,要返回的页面从左边隐藏平移到屏幕上,原来的页面平移到右边隐藏。由于项目用的是Vue3,我就用vue作为代码演示。
transition 组件
由于vue提供了一个过渡动画的标签transition,那么在这里我就不重复造轮子了,直接用这个标签来实现过度效果。简单介绍下transition这个标签。 1、必需只能包含一个根元素 2、主要是针对于v-if、v-show或路由动态组件,增加动态过渡效果 3、可根据name自定义过渡动画效果 4、自定义动画类名 -enter、 -leave、-enter-active、 -leave-active、-enter-to、-enter-to
具体使用方法可到官网查看,这就不过多介绍了。
开始实现
App.vue 改造
为了实现全局的页面切换效果,所以直接在App.vue中将router-view
包裹,实现代码如下:
html
<router-view v-slot="{ Component }">
<transition :name="transName">
<keep-alive :include="includeRoute">
<component :is="Component" :key="$route.name" v-if="$route.meta.keepAlive" />
</keep-alive>
</transition>
<transition :name="transName + 'normal'">
<component :is="Component" :key="$route.name" v-if="!$route.meta.keepAlive" />
</transition>
</router-view>
注意,这里使用两个transition是需要考虑如果有部分页面是keep-alive,有部分不是的情况,需要赋予不同的name值
判断当前路由前进还是后退
1、首先在定义路由时需要增加路由层级,用于后续判断页面是前进还是后退。代码如下:
javascript
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'app',
redirect:'/home',
},
{
path: '/home',
name: 'home',
component: () => import(/* webpackChunkName: "home" */ './home.vue'),
meta: {
title: '首页',
keepAlive: true,
deepth: -1
}
},
{
path: '/page1',
name: 'page1',
component: () => import(/* webpackChunkName: "page1" */ './page1.vue'),
meta: {
title: 'page1',
keepAlive: true,
deepth: 1
}
},
{
path: '/page2',
name: 'page2',
component: () => import(/* webpackChunkName: "page2" */ './page2.vue'),
meta: {
title: 'page2',
keepAlive: false,
deepth: 2
}
},
];
const router = createRouter({
history: createWebHistory('/'),
routes
});
export default router;
2、根据路由切换,判断页面的前进后退状态,动态改变transition的name,用来实现不同的过渡效果
typescript
// 监听当前路由的变化
watch(
() => router.currentRoute.value,
(newValue: any, oldValue: any) => {
if (newValue?.meta?.deepth && oldValue?.meta?.deepth) {
if (oldValue.meta.deepth <= newValue.meta.deepth) {
transName.value = 'push';
} else {
transName.value = 'back';
}
}
},
{ immediate: true }
);
3、css部分实现,主要定义页面前进后退时的动画效果
css
.push-enter-active {
animation-name: push-in;
animation-duration: 0.5s;
}
.push-leave-active {
animation-name: push-out;
animation-duration: 0.5s;
}
.pushnormal-enter-active {
animation-name: push-in;
animation-duration: 0.5s;
}
.pushnormal-leave-active {
animation-name: push-out;
animation-duration: 0.5s;
}
@keyframes push-in {
0% {
transform: translate(100%, 0);
}
100% {
transform: translate(0, 0);
}
}
@keyframes push-out {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(-100%, 0);
}
}
.back-enter-active {
animation-name: back-in;
animation-duration: 0.5s;
}
.back-leave-active {
animation-name: back-out;
animation-duration: 0.5s;
}
.backnormal-enter-active {
animation-name: push-in;
animation-duration: 0.5s;
}
.backnormal-leave-active {
animation-name: back-out;
animation-duration: 0.5s;
}
@keyframes back-in {
0% {
width: 100%;
transform: translate(-100%, 0);
}
100% {
width: 100%;
transform: translate(0, 0);
}
}
@keyframes back-out {
0% {
width: 100%;
transform: translate(0, 0);
}
100% {
width: 100%;
transform: translate(100%, 0);
}
}
注意
为了实现两个页面能左右切换,所以在定义每个页面样式时需要使用fixed布局
css
#app>div {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
写在最后
在前端开发中通过实现一些动态效果,在用户使用体验上都能得到较大的改善,作为前端页面优化的一部分,有更多的动画效果值得我们花时间去研究。欢迎点赞收藏,关注我,了解更多的前端知识。