多个路由使用了同一个组件,如何同时缓存这些路由对应的同一个页面。

170 阅读2分钟

最近用vue-element-amdin写后台管理系统,其中有两个页面几乎一摸一样,所以用了同一个组件(下面用cpn代替),但是路由不同。

     {
        path: 'routeA',
        component:  () => import('@/views/Page/index')
        name: 'PageA',
        meta: { title: '页面A' }
      },
      {
        path: 'routeB',
        component:  () => import('@/views/Page/index')
        name: 'PageB',
        meta: { title: '页面B' }
      },

这样写就有个问题,产品希望通过tag切换的时候,这两个路由的页面都要缓存。我们知道vue-element-amdin是通过判断组件名和路由名是否相同来决定是否缓存这个页面的。这里由于只有一个组件,所以组件名也只有一个,那只能缓存一个路由对应的页面。 如何解决这种问题呢? 方法一: 新建两个组件,组件的名字分别叫PageA和PageB,然后在这两个组件都引入cpn组件作为子组件。

// 组件A
<template>
  <cpn></cpn>
</template>
<script>
import cnp from '@/views/Page/index';
export default {
  name: 'PageA,
  components: {
    cpn,
  },
};
</script>
// 组件B
<template>
  <cnp></cnp>
</template>
<script>
import cnp from '@/views/Page/index';
export default {
  name: 'PageB,
  components: {
    cnp,
  },
};
</script>

然后再路由中的component分别使用这两个组件A和B。 这样做其实是只缓存了这个cpn组件的父组件A和B。有个弊端就是,如果想切换到A或B的时候,每次都能刷新页面的接口是无法做到的。因为这个cpn组件没有被缓存,所以不会执行activated钩子。而mounted钩子只会在第一次新开tag 的时候执行,后面切换tag是不会再执行的。 方法二: 在路由文件route.js里新增一个createCustomComponent方法,用来生成包含cpn的父组件。

const createCustomComponent = (name, component) => {
  return {
    name,
    data() {
      return { component: null }
    },
    async created() {
      if (component instanceof Promise) {
        try {
          const module = await component
          this.component = module?.default
        } catch (error) {
          console.error(`can not resolve component ${name}, error:`, error)
        }

        return
      }
      this.component = component
    },
    render(h) {
      return this.component ? h(this.component,) : null
    },
  }
}
     {
        path: 'routeA',
        component:createCustomComponent('PageA', import('@/views/Page/index')),
        name: 'PageA',
        meta: { title: '页面A' }
      },
      {
        path: 'routeB',
        component:createCustomComponent('PageA', import('@/views/Page/index')),
        name: 'PageB',
        meta: { title: '页面B' }
      },

这样的目的和方法一是一样的,只不过方法二是通过render函数来生成父组件。