一、问题描述
- 页面A在的include中,进入页面A后,在除了页面A的其他界面退出登录,并没有顺利退出到登录界面,并且菜单界面左侧空白;查看后台发现有报错
- 进行了appStore.resetCachedView后,在include中的页面退出登录,不会报错,而不在include中的页面退出登录后,还是会报错
二、问题解决
可能原因分析
- 确定如果不开启页面缓存,则不会出现如下现象,所以初步排查为:开启页面缓存后,因为退出登录时,include中的依旧有标明缓存页面,所以导致部分内容没有被销毁导致
- 于是在退出登录时,清除include中的内容
const logout = async () => {
appStore.resetCachedView();// 清除cachedView
......
};
- 进行appStore.resetCachedView后,页面正常退出至登录页面,但是后台还是会有Cannont read properties of null (reading 'nextSibling')的报错
- 后面发现注释掉transition之后,就不会有对应报错了,搜索后可知:transition和keepalive之间有时会存在冲突;
是Vue提供的用于处理组件过渡效果的组件。它可以包裹需要过渡的元素,并使用一系列钩子函数来触发不同的过渡状态。
在使用 时,如果在缓存的组件内部使用了过渡效果(例如使用了包裹组件),则可能会与产生冲突,从而导致报错。
这种问题通常是因为过渡效果与缓存组件的生命周期钩子函数(如mounted, beforeUnmount等)之间的执行顺序冲突导致的。
要解决此问题,可以尝试使用Vue提供的过渡钩子函数,如beforeEnter和afterLeave来替代组件的生命周期钩子函数。
综上所述,问题的原因是在缓存的组件内部使用了过渡效果,并且过渡效果与缓存机制冲突。解决方法是使用过渡钩子函数或Vue官方的过渡封装组件来处理过渡效果,并确保与兼容。
- 但是系统中,是 外包裹着
而如果是 外包裹着 ,而触发报错,可能是:
在 Vue 3 中,如果页面或某个组件正在进行动画处理,此时进行卸载可能导致不同步的更新或组件的销毁,从而产生错误。 和 配合使用时需要特别小心,因为 的动画效果可能会干扰 缓存的组件的正确卸载。和之间的交互,可能会导致在组件卸载时出现一些意外的行为。
在退出登录时,如果当前页面是不在include中的页面,会先卸载当前页面组件,然后再卸载include中包含的页面组件,最终加载登录界面,这时可能会出现报错"Cannot read properties of null (reading 'nextSibling')",因为当前页面组件的DOM元素可能已经在上一步卸载的时候被销毁了,并且组件销毁时,因为被transiton包裹,是会触发过渡动画的,过渡动画涉及到对DOM的操作。
而如果当前页面在include中,由于该组件未被销毁,因此在卸载时不会报错,因为卸载的时候组件的DOM元素还存在。
最终解决方案
由于和之间的交互很容易引起的冲突,所以考虑一下几种解决方案:
- 使用keepalive的缓存时,不使用transition组件
- 退出登录时,取消transition的使用
- 使用一个标志来追踪动画的状态,并确保仅在动画完成后才允许组件的卸载,可以结合 的事件来实现这一点。
<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>