最近用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函数来生成父组件。