vue3.0 使用 keep-alive 标签无效, 及其在 vue admin Layout 多级嵌套下出现问题

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

先说一下问题所在,虽然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

vue3.0 使用 keep-alive 标签无效, 及其在 vue admin Layout 多级嵌套下出现问题_第1张图片

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

vue3.0 使用 keep-alive 标签无效, 及其在 vue admin Layout 多级嵌套下出现问题_第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 都不会被调用了

vue3.0 使用 keep-alive 标签无效, 及其在 vue admin Layout 多级嵌套下出现问题_第3张图片

解决方案

两个父级组件共同一个组件
vue3.0 使用 keep-alive 标签无效, 及其在 vue admin Layout 多级嵌套下出现问题_第4张图片
这里只会有一个组件, 所以 mounted 只会打印一次
vue3.0 使用 keep-alive 标签无效, 及其在 vue admin Layout 多级嵌套下出现问题_第5张图片
点击另外一个路由后的效果, 很正常
vue3.0 使用 keep-alive 标签无效, 及其在 vue admin Layout 多级嵌套下出现问题_第6张图片

在 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 代码
vue3.0 使用 keep-alive 标签无效, 及其在 vue admin Layout 多级嵌套下出现问题_第7张图片
Test 代码
vue3.0 使用 keep-alive 标签无效, 及其在 vue admin Layout 多级嵌套下出现问题_第8张图片

社区的解决方案

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

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

element admin issue 解决方案

你可能感兴趣的:(前端问题杂记,vue.js,javascript,前端)