vue3.0 使用 keep-alive 标签无效, 及其在 vue admin Layout 多级嵌套下出现问题
先说一下问题所在,虽然vue3.0 不需要 root div, 但是keep-alivetransition这两个标签都需要。
解决方案在下面, 可以直接跳过, 这是我遇到的一些问题
先说一下问题所在,虽然vue3.0 不需要 root div, 但是
keep-alivetransition这两个标签都需要
错误示范
root div 不能加在 component 外层
<transition v-if="settings.mainNeedAnimation" name="fade-transform" mode="out-in">
<keep-alive :include="cachedViews">
<div>
<component :is="Component" :key="key" />
</div>
</keep-alive>
</transition>
正确使用
路由组件使用
<router-view v-slot="{ Component }">
<transition name="fade-transform" mode="out-in">
<keep-alive :include="cachedViews">
<component :is="Component" />
</keep-alive>
</transition>
</router-view>
路由页面代码(记住你的单个页面一定要使用一个 root div),例如下面是一个.vue 文件
<template>
<div>
<div></div>
<div></div>
<div></div>
xxxxxxxxxxxxxxx
</div>
</template>
如果你是多级路由, 每一个 router-view 内部都是需要 keep-alive 包裹, keep-alive 内部不能有任何判断条件, 要简约到只有上面例子的代码
这里是我遇到的问题
后文:
醉了, 贴个文章链接都不让, 真踏马的闭关锁国
vue element admin 中所遇到的问题
路由结构, 这里所有的父级路由都已经使用 keepalive
{
path: '/metadata',
component: View,
name: 'Meta',
// redirect: '/metadata/caliber',
meta: {
title: '元数据',
skipShow: true,
},
children: [
{
path: 'caliber',
name: 'Meta_Caliber',
// redirect: '/metadata/caliber/dimension',
component: LayoutVue,
meta: {
title: '口径管理',
icon: 'sidebar-manage',
alwaysShow: true,
},
children: [
{
path: 'test',
name: 'Test',
component: () => import('@/views/test1/index.vue'),
meta: {
title: '测试1',
},
children: [{
path: 'subTest',
name: 'TestSub',
component: () => import('@/views/test1/TestSub.vue'),
meta: {
title: '测试Sub',
},
}],
},
{
path: 'test2',
name: 'Test2',
component: () => import('@/views/test2/index.vue'),
meta: {
title: '测试2',
},
children: [{
path: 'subTest2',
name: 'TestSub2',
component: () => import('@/views/test2/TestSub2.vue'),
meta: {
title: '测试Sub2',
},
}],
},
}
这 devtools 里面可以看到 TestSub2 组件不正常的归属于两个父级组件, 一个处于没有激活的 Test , 一个是已经激活的 Test2

下面是我测试的 mounted 打印, 这里的 TestSub2 mounted 生命周期被重复调用2次

test2 代码
<script setup lang="ts">
const count = ref(0)
onMounted(() => {
console.log('Test2');
})
</script>
<script lang="ts">
export default {
name: 'Test2',
}
</script>
<template>
<div class="">
Test2
<div @click="count++">
{{ count }}
</div>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
</div>
</template>
<style lang="scss"></style>
TestSub2 代码
<script setup lang="ts">
const count = ref(0)
onMounted(() => {
console.log('TestSub2');
})
</script>
<template>
<div class="">
TestSub2
<div @click="count++">
{{ count }}
</div>
</div>
</template>
<style lang="scss"></style>
当我多次点击菜单后, Test, Test2 两个组件都已经拥有了两个子组件, 在这里不知道为什么, 然后因为两个组件都已经被缓存, 此时的 mounted 都不会被调用了

解决方案
两个父级组件共同一个组件
这里只会有一个组件, 所以 mounted 只会打印一次
点击另外一个路由后的效果, 很正常
在 vue element admin 代码里面的多级路由存在一个问题, tagview 组件中一个往 cacheview 添加组件name的方法
const addTags = () => {
if (route?.name && !route.meta.noCache) {
tagsViewStore.addVisitedView({ ...route })
}
return false
}
当一个路由拥有 redirect 属性的时候, 那么这个方法将无法把他的name 添加到 cacheview 数组里面, 而是把他重定向的子级name添加进去了。因为keepalive 是对直接自己组件生效的, 那么缓存就会失效, 可以创建一个 Test 组件(名字随便取,但是需要的keepalive的数组中注意一定要准确, 他可以是公用的, 所有的同级路由都可以用它来当做 Routeview 页面), 用它来占位;然后在 AppMain 的 keepalive 里面提前写上这个组件的 name, 此时你可能会考虑到怎么解决当我关闭 tagview 的标签时怎么关闭缓存, 你可以在 Test 组件的 keepalive上关联到 cacheviews, 当你关闭tag时, 这个路由的name就被删除了, 也就是说缓存的关键是 Test 这个组件的keepalive的数组中存在哪些name, 就算是 Test 一直被缓存, 但是他可以控制谁会被自己缓存
AppMain 代码
Test 代码
社区的解决方案
把所有超过二级的路由铺平为二级路由
vue vben 项目用的就是这个方案, 感兴趣的可以去看看
更多推荐



所有评论(0)