使用缓存前,建议先读一遍官方文档 ;以及可以先注意本文列举的注意项和不生效原因
一、使用keep-alive的两种方式
1.通过v-if="$route.meta.keepAlive"
方式
1.1代码:
注意:一定要设置:key
,否则在两个都是缓存的页面跳转回报错
{{$route.meta}}-{{$route.meta.keepAlive}}
<router-view v-slot="{ Component }">
<!-- 一定要设置:key="route.name" 否则在两个连续缓存页跳转会报错 -->
<keep-alive>
<component v-if="$route.meta.keepAlive" :key="$route.path" :is="Component" />
</keep-alive>
<component v-if="!$route.meta.keepAlive" :key="$route.path" :is="Component" />
</router-view>
1.2配置对用keepAlive
2.通过include
方式
2.1代码:
- 注意::include="[‘experienceMaintenance’, ‘realTimeAlarm’]"
使用的是vue页name,不是路由的name
- 建议: vue页name和路由的name保持一致,这样在做缓存时候,方便监听存入
<router-view v-slot="{ Component }">
<!--:key 每次切换时,通过修改 key 的值,可以避免缓存中的组件被复用,从而达到刷新组件的目的-->
<!-- :key="$route.path" -->
<keep-alive :include="['DeviceList','ExperienceMaintenance', 'RealTimeAlarm']">
<component :is="Component"></component>
</keep-alive>
</router-view>
监听路由变化
watch(route, val => {
const { path, matched } = val
if (!matched.length) return
console.log('页签监听', path, val, matched,)
console.log('vue组件名name和vue路由name设置一致,就可以直接取该name存入缓存集合', val.name);
// let keepAliveName = matched[matched.length - 1].name
// console.log('keepAliveName', keepAliveName);
}, { immediate: true, deep: true })
1.2设置对应vue页组件name
3.区别
- 使用v-if=的方式,配置简单。只需要在路由文件里给需要缓存的配置keepAlive
meta: { title: "经验维护", keepAlive: true }
- 使用include的需要给每一个vue页配置name,很麻烦。但是该方式的
应该有优点吧?
; 例如一个vue页面可以缓存具体的组件
二、keep-alive缓存不生效原因
1.路由文件配置有误
- 在路由文件里面,将需要keep-alive的页面放在layout组件的children里面(如果不放在children里面keep-alive就不会生效)—layout组件就是你写keep-alive的那个组件;需要给要缓存的页面的一级菜单配置相同的component
- 例子:有A、B、C三个一级菜单,其下下分别有对应a1、a2、b1、b2、c1、c2的二级路由,且都要缓存。那么
ABC的三个一级菜单的component:引入需要一致
;否则a1、a2跳转时候缓存正常,但是a1、b1、c1这种跨了不同一级菜单的相互跳转,会发现缓存不生效。
2.使用include设置name不生效
- 注意name应该是vue页面的name,不是路由里的name
- 需要使用:key=区分 否则切换路由报错
3.使用对用钩子函数
- vue导航守卫触发实际和顺序
- 首先vue3是onBeforeRouteLeave这个钩子的,但是beforeRouteEnter钩子函数不存在了;不过可以通过代码实现beforeRouteEnter钩子函数
3.1 正常使用onBeforeRouteLeave
<script setup>
import { ref, onMounted, onActivated, onDeactivated} from "vue"
import { onBeforeRouteLeave } from 'vue-router'
onActivated(() => {
console.log('onActivated');
// 调用时机为首次挂载
// 以及每次从缓存中被重新插入时
})
onDeactivated(() => {
console.log('onDeactivated');
// 在从 DOM 上移除、进入缓存
// 以及组件卸载时调用
})
// 将变量和函数返回,以便在模版中使用
onBeforeRouteLeave((to, from, next) => {
console.log('onBeforeRouteLeave==',to, from.meta, next);
// from.meta.keepAlive = false
// console.log(from.meta);
next()
// const cacheList = ['组织']
// if (cacheList.indexOf(to.name) === -1) {
// doing()
// nextTick(() => {
// })
// }
})
3.2 实现beforeRouteEnter
- vue3无beforeRouteEnter,可以实现;参考链接
<script setup>
defineOptions({
name: 'ExperienceMaintenance',
beforeRouteEnter(_to, _from, next) {
console.log('beforeRouteEnter执行',_to, _from, next);
next((vm) => {
const instance = vm
instance.getData() // 刷新列表数据(不缓存)
})
}
})
const getData = async () => {
console.log('出发对应方法');
}
// * beforeRouteEnter中要用到的方法,需要暴露出来
defineExpose({ getData })
</script>
参考点:路由配置里也有独享的守卫beforeEnter
三、注意项
1.报错[vite] Internal Server Error expects exactly one child component.at createCompilerError
报错:
原因: 由于 <
keep-alive
> 是一个组件,而不是普通的HTML标签,所以在其内部是不能直接写注释的。
方法:
2.报错TypeError: parentComponent.ctx.deactivate is not a function
注意:一定要设置:key,否则在两个都是缓存的页面跳转回报错