需求
在使用elmenui的el-pagination时,用户从列表页如第二页进入详情页进行操作后,返回列表页时,列表应该显示第二页的内容,而不是第一页。
解决办法
1.使用路由跳转传参存储页码
从列表页跳转到详情页时,将当前页的页码再路由跳转时传递给详情页,再从详情页跳转回列表页时,传递回页码。
// 从列表页跳转到详情页
toDetial () {
this.$router.push({ name: 'Detail', query: { pageNum: this.queryParams.pageNum } });
},
// 从详情页跳转到列表页 传递回页码
toList () {
this.$router.push({ name: 'List', query: { pageNum: this.$route.query.pageNum } });
},
//在列表页中获取页码
created () {
// 当路由参数不存在时 默认取第一页数据
this.queryParams.pageNum = this.$route.query.pageNum || 1
// 调用获取列表数据方法
this.getListData()
}
2.使用vuex存储页码
// 当页码变化时
handleCurrentChange (val) {
this.queryParams.pageNum = val;
// 将当前页数保存到vuex中
this.$store.commit('currentPage', val);
this.getList();
},
// 从详情页返回时让当前页等于vuex中保存的页码数
created () {
this.queryParams.pageNum = Number(this.$store.state.pageNum) || 1;
this.getList();
},
// 当访问的页面不是详情页时,初始化vuex中保存的当前页信息
beforeRouteLeave (to, form, next) {
if (to.name && to.name !== 'Detail') {
this.$store.state.pageNum = undefined;
}
next();
},
3.使用keep-alive组件缓存整个页面
1.根据是否需要缓存定义2个router-view
// 需要缓存的组件
<keep-alive >
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
// 不需要缓存的组件
<router-view v-if="!$route.meta.keepAlive"></router-view>
2.在Router里定义好需要缓存的路由组件
new Router({
routes: [
{
path: '',
component: Layout,
redirect: '/goods',
hidden: false,
name: '商品管理',
meta: {
title: '商品管理',
noCache: true,
icon: 'documentation'
},
children: [{
path: 'goods',
component: () => import('@/pages/goods/index'),
name: 'goodsList',
meta: {
title: '商品列表',
keepAlive: true //需要缓存
}
}, {
path: 'goods/goodsDetail',
component: () => import('@/pages/goods/goodsDetail'),
hidden: true,
name: 'goodsDetail',
meta: {
title: '商品详情',
keepAlive: true //需要缓存
}
},
...
]
})
3.activated和deactivated
被keepAlive包裹的组件,会多出2个生命周期钩子函数 activated 和 deactivated。
activated在缓存的组件第一次渲染时会被调用,之后在每次缓存的组件被激活时调用,相当于小程序中的onShow()。
activated触发时机:
1.第一次进入缓存的组件时:activated在mounted之后,beforeRouteEnter回调执行之前被调用。
beforeRouteEnter --> beforeCreated --> created --> beforeMount -->若从其他路由组件进入
(组件销毁destroyed/或离开缓存deactivated)--> mounted --> activated --> beforeRouteEnter回调
2.之后再次进入缓存的组件时:beforeCreate created beforeMount mounted 都不会触发,只会触发activated以及deactivated。
beforeRouteEnter --> 组件销毁destroyed/或离开缓存deactivated --> activated --> beforeRouteEnter回调
deactivated在每次离开缓存的组件时会被调用,相当于小程序中的onHide()。
deactivated触发时机:
1.如果离开的组件有缓存(被keepAlive包裹的路由组件),则执行deactivated,不会执行beforeDestroy以及destroyed。
beforeRouteLeave --> beforeEach --> beforeRouteEnter--> afterEach --> deactivated
2.如果离开的路由组件没有缓存(不被keepAlive包裹的路由组件),则执行deactivated,beforeDestroy以及destroyed。
beforeRouteLeave --> beforeEach --> beforeRouteEnter--> afterEach --> deactivated -->
beforeDestroy -->destroyed
4.按需缓存
keep-alive props:
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例。
include 和 exclude prop 允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示。
keep-alive组件如果设置了include属性,则就只有和include匹配的组件会被缓存。
<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
<router-view v-if="$route.meta.keepAlive"> </router-view>
</keep-alive>
<!-- 不需要缓存的视图组件 -->
<router-view v-if="!$route.meta.keepAlive"> </router-view>
<!-- 正则表达式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
<router-view v-if="$route.meta.keepAlive"> </router-view>
</keep-alive>
<!-- 不需要缓存的视图组件 -->
<router-view v-if="!$route.meta.keepAlive"> </router-view>
<!-- 数组 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
<router-view v-if="$route.meta.keepAlive"> </router-view>
</keep-alive>
<!-- 不需要缓存的视图组件 -->
<router-view v-if="!$route.meta.keepAlive"> </router-view>
在app.vue中监听路由变化
export default {
name: "app",
data: () => ({
include: []
}),
watch: {
$route(to, from) {
//如果 要 to(进入) 的页面是需要 keepAlive 缓存的,把 name push 进 include数组
if (to.meta.keepAlive) {
!this.include.includes(to.name) && this.include.push(to.name);
}
//如果 要 form(离开) 的页面是 keepAlive缓存的,
//再根据 deepth 来判断是前进还是后退
//如果是后退
if (from.meta.keepAlive && to.meta.deepth < from.meta.deepth) {
var index = this.include.indexOf(from.name);
index !== -1 && this.include.splice(index, 1);
}
}
}
};
总结:
只简单缓存页码可以使用路由跳转传参或者vuex存储页码,若想缓存整个页面,包括查询筛选条件等,则使用keep-alive组件。
另外,还可以使用sessionStorage存储当前页码,与使用vuex方法类似。
如果大家有更好的方法实现,欢迎讨论交流。