一、业务场景示例
页面A: 数据列表,有一些查询条件,如查询条件区域,查询结果为区域信息列表
页面B: 数据详情,点击列表任意一条记录,跳转到对应的区域详情
期望:在页面B,点击浏览器返回按钮,显示上一次页面A查询结果与查询条件(最好不从新请求)
二、实现
利用vue的keep-alive,使用keep-alive可以是组件在第一次创建时被缓存下来,离开页面时不销毁
使用了
keep-alive生命周期
1.activated:页面第一次进入的时候,钩子触发的顺序是created->mounted->activated
2.deactivated :页面退出的时候会触发deactivated,当再次前进或者后退的时候只触发activated
修改路由注册文件
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component"
v-if="$route.meta.keepAlive"
:key="$route.path" />
</keep-alive>
<component :is="Component"
v-if="!$route.meta.keepAlive" />
</router-view>
在需要缓存的页面路由中配置keepAlive: true
{
name: 'A',
path: '/A',
component: () => import(/* webpackChunkName: "home" */ '@/views/A.vue'),
meta: {
keepAlive: true,
},
}
添加统一判断是否是返回
router.afterEach((to) => { // 一定要再afterEach中判断而不是beforeEach,因为beforeEach在点击返回之后获取到的值不准确,每返回一次,会获取到延后一次的to、history
if (window.history.state && window.history.state.forward) { // 或者判断 to.forward,window.history.state.forward是vue-router写入的,当返回或前进的时候才会有值
to.meta.isBack = true;
} else {
to.meta.isBack = false;
}
});
在使用的页面
const isInit = ref(true); // 解决window.history.state.forward是否存在判断是否返回不准确问题
onMounted(() => {
submitSearchForm(); // 请求查询数据
});
const routes = useRoute();
const searchFormRef = ref();
onActivated(() => {
if (!routes.meta.isBack && !isInit.value) { // 如果不是返回还是需要请求更新数据的
searchFormRef.value.resetFields(); // 这是ant-design-vue提供的重置表单的方法,如果没用,可以手动重置
submitSearchForm(); // 请求查询数据
}
isInit .value = false;
});
三、采坑总结
1.不要动态修改to.meta.keepAlive的值控制是否缓存。
会存在第一次将to.meta.keepAlive设置为true是还是会发送请求,因为第一次是创建组件,没有缓存,需要缓存后,下一次进入才不会发送请求。因为如果最开始进入的时候to.meta.keepAlive值为false的话,渲染的是没有使用keep-alive的组件。
2.通过forward判断是否是返回,需要再afterEach中
因为beforeEach在点击返回之后获取到的值不准确,每点击一次返回,会获取到延后一次的to、history中的值
3.需要再中间中配置key值,来表示组件的唯一性和对应关系,如::key="$route.path"
如果不配置key值,当多个页面配置keepAlive:true时,在切换缓存页面时会报错Uncaught (in promise) TypeError: parentComponent.ctx.deactivate is not a function