解决方案在下面, 可以直接跳过, 这是我遇到的一些问题

先说一下问题所在,虽然vue3.0 不需要 root div, 但是 keep-alive transition 这两个标签都需要

错误示范

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 页面), 用它来占位;然后在 AppMainkeepalive 里面提前写上这个组件的 name, 此时你可能会考虑到怎么解决当我关闭 tagview 的标签时怎么关闭缓存, 你可以在 Test 组件的 keepalive上关联到 cacheviews, 当你关闭tag时, 这个路由的name就被删除了, 也就是说缓存的关键是 Test 这个组件的keepalive的数组中存在哪些name, 就算是 Test 一直被缓存, 但是他可以控制谁会被自己缓存

AppMain 代码
在这里插入图片描述
Test 代码
在这里插入图片描述

社区的解决方案

把所有超过二级的路由铺平为二级路由

vue vben 项目用的就是这个方案, 感兴趣的可以去看看

element admin issue 解决方案

Logo

前往低代码交流专区

更多推荐