两步
关于keep-alive无法缓存多级菜单的解决,之前使用老版本的若依框架,无法做到多级菜单之间切换的一个缓存,这里三步聊聊如何把多级菜单拍平成为一级菜单
一、处理后台数据
1.—vuex —permission.js
在vuex拿到后台路由数据的时候进行拍平。拿到的是一个有children的多级数组,我们遍历成一个单级的数组然后addroutes到路由中。但是显示在侧边栏的依然时多级数组。完成这一步,应该可以通过路径访问到页面了,就像访问静态路由一样。代码如下:
GenerateRoutes({state, commit }) {
return new Promise(resolve => {
// 向后端请求路由数据
getRouters().then(res => {
const sdata = JSON.parse(JSON.stringify(res.data))
const rdata = JSON.parse(JSON.stringify(res.data))
const sidebarRoutes = filterAsyncRouter(sdata)
const rewriteRoutes = filterAsyncRouter(rdata, true)
rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
commit('SET_ROUTES', rewriteRoutes)
commit('SET_SIDEBAR_ROUTERS', sidebarRoutes) //这里的数据用于展示
let newList=[]
deepOpen(rewriteRoutes,newList)
//console.log(rewriteRoutes);
resolve(newList) //返回一级路由数组
})
})
}
//拍平一级路由的方法
function deepOpen(list,newList){
list.forEach(item => {
if(!item.children){
newList.push(
{
path: '/'+item.path,
component: Layout,
hidden: true,
children: [
{
path: item.path,
component: item.component,
name: item.name,
meta: item.meta,
}
]
},
)
}else{
deepOpen(item.children,newList)
}
});
}
二、处理路径
—layout —Sidebar --SidebarItem.vue
在布局文件的侧边栏中,修改路径为我们之前设置的路径,要一模一样就ok了,之前设置的是path接上子组件的path所以是两个path /path/path
这里直接上这个组件全部文件代码
<template>
<div v-if="!item.hidden">
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
<app-link v-if="onlyOneChild.meta" :to="resolvePath(item.path)">
<el-menu-item :index="'/'+item.path+'/'+item.path" :class="{'submenu-title-noDropdown':!isNest}">
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
</el-menu-item>
</app-link>
</template>
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
<template slot="title">
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
</template>
<sidebar-item
v-for="child in item.children"
:key="child.path"
:is-nest="true"
:item="child"
:base-path="resolvePath(child.path)"
class="nest-menu"
/>
</el-submenu>
</div>
</template>
<script>
import path from 'path'
import { isExternal } from '@/utils/validate'
import Item from './Item'
import AppLink from './Link'
import FixiOSBug from './FixiOSBug'
export default {
name: 'SidebarItem',
components: { Item, AppLink },
mixins: [FixiOSBug],
props: {
// route object
item: {
type: Object,
required: true
},
isNest: {
type: Boolean,
default: false
},
basePath: {
type: String,
default: ''
}
},
data() {
this.onlyOneChild = null
return {}
},
methods: {
hasOneShowingChild(children = [], parent) {
const showingChildren = children.filter(item => {
if (item.hidden) {
return false
} else {
// Temp set(will be used if only has one showing child)
this.onlyOneChild = item
return true
}
})
// When there is only one child router, the child router is displayed by default
if (showingChildren.length === 1) {
return true
}
// Show parent if there are no child router to display
if (showingChildren.length === 0) {
this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
return true
}
return false
},
resolvePath(routePath) {
//console.log(routePath);
//return routePath
// if (isExternal(routePath)) {
// console.log(1);
// return routePath
// }
// if (isExternal(this.basePath)) {
// console.log(2);
// return this.basePath
// }
// return path.resolve(this.basePath, routePath)
// /console.log(routePath);
return routePath
}
}
}
</script>
重点是resolvePath方法 注意一下传的参数 这里用的是item.path
还有就是applink组件的跳转路径也处理一下,当然我的路径是在这边处理的,你可以直接在上一个组件修改
linkProps(to) {
if (this.isExternal) {
return {
href: '/'+to+'/'+to,
target: '_blank',
rel: 'noopener'
}
}if(!to){
return {
to: '/'
}
}
return {
to: '/'+to+'/'+to
}
},
注意:如果修改完侧边栏的active颜色要点两下才高亮的话,是因为那个default-active的值和el-menu-item的index不一致,改成一样就可以了
这边参考下中间那块代码块的
:index="’/’+item.path+’/’+item.path"