持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
最近做项目时遇到这样一个需求,有这样三个页面,首页(A) -> 列表页(B) -> 详情页(C),从A进入B,B不需要缓存,B进入C,此时要把B缓存起来,保存B页面加载的数据和滚动位置。
我们在vue3中,结合keep-alive、vue-router来实现这个功能
1.App.vue 常规设置
在App.vue中,使用keep-alive,并根据路由meta的keepAlive属性来判断是否需要缓存组件;keep-alive大家都很熟悉,如果启用,页面会被缓存。
<router-view v-slot="{ Component }">
<keep-alive>
<component
:is="Component"
v-if="$route.meta.keepAlive"
:key="$route.name"
/>
</keep-alive>
<component
:is="Component"
v-if="!$route.meta.keepAlive"
:key="$route.name"
/>
</router-view>
2.设置router
meta里面的keepAlive字段用来设置页面是否需要缓存,主要给keep-alive组件使用
[{
path: '/',
name: 'A',
component: () => import('@/views/A/index.vue'),
meta: {
title: '首页',
keepAlive: false // 此组件不需要被缓存
}
},
{
path: '/B',
name: 'B',
component: () => import('@/views/B/index.vue'),
meta: {
title: '列表',
keepAlive: false
}
},
{
path: '/C',
name: 'C',
component: () => import('@/views/C/index.vue'),
meta: {
title: '详情',
keepAlive: false
}
}]
到这里,思路就来了,我们可以结合组件路由钩子,在页面跳转的时候,去改变meta的keepAlive值;在B页面设置路由钩子,判断B页面是进入A还是C,如果是C,那么设置B页面,如果是A,那么反之。
3.新建useKeepPage.ts
因为用的是vue3,把这个功能写成一个hooks。
不得不说vue3的Composition API确实好用
import { onBeforeRouteLeave } from 'vue-router'
// 这里把targetPages参数设置为数组,因为目标页面可能有多个,比如B -> C, B -> D
export function useKeepPage(targetPages: string[]) {
const router = useRouter()
/**
* @description: 更新路由meta.keepAlive值
* @param {name} string 需要修改的路由名称
* @param {val} boolean 修改的值
* @return {*}
*/
const updateRouterKeepAlive = (name: string, val: boolean) => {
const recursiveFn = (routes: readonly RouteRecordRaw[]) => {
routes.forEach((item) => {
if (item.name === name) {
item.meta!.keepAlive = val
} else if (item.children){
recursiveFn(item.children)
}
})
recursiveFn(router.options.routes)
}
}
/**
* @description: 设置页面缓存
* @param {toName} string 目标页面name
* @param {formName} string 来源页面name
* @return {*}
*/
const setKeepPage = (toName: string, fromName: string) => {
// 判断是否进入目标页面
if (!targetPages.includes(toName)) {
updateRouterKeepAlive(fromName, false)
} else {
updateRouterKeepAlive(fromName, true)
}
}
// 设置路由钩子
onBeforeRouteLeave((to, from) => {
setKeepPage(to.name as string, from.name as string)
})
return {
setKeepPage,
updateRouterKeepAlive
}
}
这里其实有一个坑,一开始我是直接在路由钩子里面改keepAlive的值,但是这样改并不生效,这就是为什么写一个updateRouterKeepAlive方法的原因,我们需要去遍历router源信息,找到需要修改的对应路由更改。
4.最后,在相应的页面引用useKeepPage就可以了
page B.vue
<script lang='ts' setup>
import { useKeepPage } from '@/hooks/useKeepPage'
useKeepPage(['C'])
</script>