vue3使用keep-alive做缓存;vue3实现beforeRouteEnter

发布于:2024-12-18 ⋅ 阅读:(117) ⋅ 点赞:(0)

使用缓存前,建议先读一遍官方文档 ;以及可以先注意本文列举的注意项和不生效原因

一、使用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

<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,否则在两个都是缓存的页面跳转回报错