业务场景
我们在使用APP或者小程序的时候,从商品的详情页回到列表页,都会发现列表页面是没有刷新的,还是之前的状态。但是Vue的SPA(单页面应用)在使用vue-router的情况下,每次路由都会刷新页面,这和我们的业务场景是不相符的,会给用户带来不好的操作体验。
keep-alive组件
首页,必须要使用的是<keep-alive>
组件,官方对它的介绍也仅是在讲<router-view>
组件提及了一下,甚至没讲作用(甚是奇怪,或许是自己没找到)
我们的使用也是简单的,只需要第一步,启用<keep-alive>
组件
<template>
<div id="app">
<keep-alive>
<router-view v-if="$route.meta.keepAlive" />
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" />
</div>
</template>
可以看到,是否使用<keep-alive>
有一个条件判断,而这个判断是我们配置在routes的元信息里面的
第二步,在需要缓存的页面的routes配置的元信息中将keepAlive设置为true,这个meta字段叫keepAlive是我们自己取的,叫什么都可以
{
path: 'signup/list',
name: 'SignUpList',
component: () => import('pages/SignUpList.vue'),
meta: { keepAlive: true }
}
两个新问题
简单的两步设置,我们期望的列表页面确实被缓存了,但是产生了两个新问题:一是只缓存了页面数据(可以看到任何网络请求被发起了),没有缓存scroll的位置(直接回到了顶部),二是在当前session内一直被缓存了,重新登录之后也是如此(因为登录仅是业务行为)
没有缓存scroll的位置
使用savedPosition,savedPosition是官方推荐使用的方式,滚动行为-官方
使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。
我们可以在,router/index.js里面这样简单的配置:
export default new VueRouter({
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { x: 0, y: 0 }
}
},
routes,
mode: process.env.VUE_ROUTER_MODE,
base: process.env.VUE_ROUTER_BASE
})
当从详情回到列表页面的scroll的缓存效果也实现了,列表页面在离开时的位置,也就是说bac(),达到了我们的业务需求,但是新问题又来了:底部的tabbar(使用router-link的replace来模拟)没有实现对scroll的缓存,列表页面回到了顶部
这不是vue-router的锅,而是业务场景特殊,但是在切换底部tab的时候我们通常也是要保留原始页面的,这也是合理的需求,这个如何设置是一个问题,不过关于这个问题我们后续讨论。
一直被缓存
有些场景下我们不希望列表页面进入的时候是缓存下的上一个页面,我们希望它重新加载数据
关于使用缓存和不使用缓存的Vue的生命周期钩子是这样的:
第一次进入:beforeRouterEnter ->created->…->activated->…->deactivated
后续进入时:beforeRouterEnter ->activated->deactivated
也就是说如果这个页面是keep-alive的话,我们可以activated里面判断是否要进行load数据,配合meta信息,我们可以轻松的做到这一点
首先,在meta里面添加一个isUseCache的字段(名字随意)
{
path: 'signup/list',
name: 'SignUpList',
component: () => import('pages/SignUpList.vue'),
meta: { keepAlive: true, isUseCache: true }
}
第二步,在缓存的页面的activated钩子函数里面判断是否重新加载数据
activated () {
if (!this.$route.meta.isUseCache) {
// 重新加载数据,包含里重置分页,设空原有数据等操作
this.reloadData()
}
},
第三步,通过路由守卫,来动态地修改列表页面的isUseCache状态,我们的业务是从某些页面进入列表页面需要要求它刷新,所以可以通过beforeRouteLeave (to, from, next)
这个钩子函数来实现这个效果,如果to是列表页面的话,将to的meta的isUseCache设置为false即可。代码如下:
beforeRouteLeave (to, from, next) {
if (to.name === 'SignUpList') {
to.meta.isUseCache = false
}
next()
},
以上一套组合拳下来,就基本实现了后退缓存这一需求,只是对于第二个问题,存在部分的代码侵入,不过这也是属于业务的一部分
其它奇怪的内容
从一个keepAlive的页面进入另一个,后者是会刷新的…
参考文章: