vue3的keepalive使用include后,切换页面出现报错~暂做记录

295 阅读4分钟

一、问题描述

  1. 页面A在的include中,进入页面A后,在除了页面A的其他界面退出登录,并没有顺利退出到登录界面,并且菜单界面左侧空白;查看后台发现有报错

  1. 进行了appStore.resetCachedView后,在include中的页面退出登录,不会报错,而不在include中的页面退出登录后,还是会报错

二、问题解决

可能原因分析

  1. 确定如果不开启页面缓存,则不会出现如下现象,所以初步排查为:开启页面缓存后,因为退出登录时,include中的依旧有标明缓存页面,所以导致部分内容没有被销毁导致
  2. 于是在退出登录时,清除include中的内容
const logout = async () => {
  appStore.resetCachedView();// 清除cachedView
......
};
  1. 进行appStore.resetCachedView后,页面正常退出至登录页面,但是后台还是会有Cannont read properties of null (reading 'nextSibling')的报错
  2. 后面发现注释掉transition之后,就不会有对应报错了,搜索后可知:transition和keepalive之间有时会存在冲突;

是Vue提供的用于处理组件过渡效果的组件。它可以包裹需要过渡的元素,并使用一系列钩子函数来触发不同的过渡状态。

在使用 时,如果在缓存的组件内部使用了过渡效果(例如使用了包裹组件),则可能会与产生冲突,从而导致报错。

这种问题通常是因为过渡效果与缓存组件的生命周期钩子函数(如mounted, beforeUnmount等)之间的执行顺序冲突导致的。

要解决此问题,可以尝试使用Vue提供的过渡钩子函数,如beforeEnter和afterLeave来替代组件的生命周期钩子函数。

综上所述,问题的原因是在缓存的组件内部使用了过渡效果,并且过渡效果与缓存机制冲突。解决方法是使用过渡钩子函数或Vue官方的过渡封装组件来处理过渡效果,并确保与兼容。

  1. 但是系统中,是 外包裹着

而如果是 外包裹着 ,而触发报错,可能是:

在 Vue 3 中,如果页面或某个组件正在进行动画处理,此时进行卸载可能导致不同步的更新或组件的销毁,从而产生错误。 和 配合使用时需要特别小心,因为 的动画效果可能会干扰 缓存的组件的正确卸载。和之间的交互,可能会导致在组件卸载时出现一些意外的行为。

在退出登录时,如果当前页面是不在include中的页面,会先卸载当前页面组件,然后再卸载include中包含的页面组件,最终加载登录界面,这时可能会出现报错"Cannot read properties of null (reading 'nextSibling')",因为当前页面组件的DOM元素可能已经在上一步卸载的时候被销毁了,并且组件销毁时,因为被transiton包裹,是会触发过渡动画的,过渡动画涉及到对DOM的操作。

而如果当前页面在include中,由于该组件未被销毁,因此在卸载时不会报错,因为卸载的时候组件的DOM元素还存在。

最终解决方案

由于和之间的交互很容易引起的冲突,所以考虑一下几种解决方案:

  1. 使用keepalive的缓存时,不使用transition组件
  2. 退出登录时,取消transition的使用
  3. 使用一个标志来追踪动画的状态,并确保仅在动画完成后才允许组件的卸载,可以结合 的事件来实现这一点。
<template>
  <!-- ... -->
  <transition
    v-if="settings.mainNeedAnimation && !animationCompleted"// 确保仅在动画完成后才允许卸载当前组件
    name="fade-transform"
    mode="out-in"
    @leave="handleLeave"
    @after-leave="afterAnimation"
  >
    <!-- ... -->
  </transition>
  <!-- ... -->
</template>
<script setup>
import { ref } from 'vue';
const animationCompleted = ref(false);
function handleLeave(el, done) {
  // 假设这里是动画的 JavaScript 钩子,根据具体动画库实现可能不同
  performAnimation(el, {
    // 动画参数 ...
  }).then(done);
}
function afterAnimation() {
  animationCompleted.value = true;
  // 动画完成后,可能需要执行一些清理操作或状态更新
}
// 其他逻辑 ...
</script>