拥有相同组件的同级路由的切换为什么会导致该组件重新实例化?

古道西风瘦马
  • 344

我项目中有类似这样一段代码

// router.js

const constantRoutes = [{
  path: '/a',
  component: () => import('@/components/HelloWorld.vue'),
  children: [{
    path: '1',
    name: 'C1',
    meta: { instanceName: 'one' },
    component: () => import('@/components/C1.vue')
  },
  {
    path: '2',
    name: 'C1-2',
    meta: { instanceName: 'tow' },
    component: () => import('@/components/C1.vue')
  }]
}, {
  path: '/b',
  component: () => import('@/components/HelloWorld.vue'),
  children: [{
    path: '1',
    name: 'C2',
    component: () => import('@/components/C2.vue')
  }]
}]

// HelloWorld.vue

<template>
  <div class="hello">
    <h3>container</h3>
    <ul>
      <keep-alive>
        <router-view :key="key" />
      </keep-alive>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  computed: {
    key() {
      return this.$route.path
    }
  },
  created () {
    console.log('helloWorld', this.$route)
  }
}
</script>

当我从a/1这个路径切换到b/1这个路径,他们共同的父组件helloWorld不会重新实例化。vue-router官方的说法也是说,当不同的路由使用同一个组件的时候,为了节省开销不会再实例化。
正常情况:
/a/1 ====> /a/2 helloWorld不会实例化
/a/2 ====> /b/1 helloWorld不会实例化

但是实际的项目中,我遇到的情况恰好相反,父组件因为一级路由的切换会重新实例化,只有切换同级路由下的二级路由才不会实例化。
项目中遇到的情况:
/a/1 ====> /a/2 不会实例化
/a/1 ====> /b/2 /a、/b对应的共同组件会重新实例化。

拥有同一组件的一级路由之间的切换,该共同的组件也会重新实例化,我百思不得其解,也不知道是什么原因,我也并没有在一级路由对应的router-view上设置key属性,希望有大佬指点指点。

大家不要纠结我为什么不把a、b合成一个路由写,因为我的这里每个一级路由都是一个一级菜单。

我的目的就是希望能缓存所有的菜单页面,但是现在这种情况只能让处在同个一级菜单下的二级菜单实现缓存,换个一级菜单就凉了。

回复
阅读 882
4 个回答

因为你a和b是两个不同的路由,只不过是用的同一个组件,你可能需要路由别名

根据你写的路由
实际上你是实例化了2个hellpworl组件 分别对应a和b
这样子改试试

const constantRoutes = [{
  path: '/',
  component: () => import('@/components/HelloWorld.vue'),
  children: [
    {
      path: '/a/1',
      name: 'C1',
      component: () =>import('@/components/C1.vue')
    },
    {
      path: '/b/1',
      name: 'C2',
      component: () => import('@/components/C2.vue')
    }
  ]
}]

如果你是想实现的是这种情况:
image.png

那么我把实例代码贴出来给你,如果是其他情况可能需要你描述的更细节一点。

// router.js
const routes = [
  {
    path: "/a",
    name: "pageA",
    component: () => import("./routerViewer"),
    children:[
      {
        path: "1",
        name: "pageA-1",
        component: () => import("./pageA")
      },
      {
        path: "2",
        name: "pageA-2",
        component: () => import("./pageA")
      },
    ]
  },
  {
    path: "/b",
    name: "pageB",
    component: () => import("./routerViewer"),
    children: [
      {
        path: "1",
        name: "pageB-1",
        component: () => import("./pageB")
      }
    ]
  },
];
// routerViewer.vue
<template>
  <keep-alive>
    <router-view :key="$route.path"></router-view>
  </keep-alive>
</template>
<script>
export default {
  name: 'router-viewer',
}
</script>
// App.vue
<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  name: 'App',
}
</script>

我的这个BUG已经修复了,感谢各位回答。
我项目中会出现一级路由共同的组件会在切换一级路由的时候重新实例化的原因是,因为我在获取后端数据递归生成路由表的时候,我使用loadsh.cloneDeep方法深拷贝了一下每个路由配置。也就是进行了类似如下的操作:

_.cloneDeep({ path: '/a', name:'A', component: () => import('@/a.vue') })

经过我的排查,我发现最大的问题就是不能拷贝这个异步加载函数import,我去掉这个函数使用普通的加载,发现一切都正常,至于更深层次的原因我也不知道为什么,如果有大佬明白,可以在这个问题下面写个答案。

宣传栏