title: "Vue+abp增加三级菜单"
publishDate: 2019-12-26 17:28:38 +0800
date: 2019-12-26 17:28:38 +0800
categories: Vue+abp增加三级菜单
position: problem
原生vue版的abp只支持2级菜单,项目需要增加成3级菜单,一番搜索。成果如下
增加3级菜单显示
修改components->shrinkable-menu->components->sidebarMenu文件,增加一级菜单,并增加两个方法hasChildren和getChildren,避免html因为没有children属性报错
<template>
<Menu ref="sideMenu" :active-name="$route.name" :open-names="openNames" :theme="menuTheme" width="auto" @on-select="changeMenu">
<template v-for="item in menuList">
<MenuItem v-if="item.children.length<=0" :name="item.children[0].name" :key="item.name">
<!-- <Icon :type="item.icon" :size="iconSize"></Icon> -->
<span class="iconfont">{{item.icon}}</span>
<span>{{ itemTitle(item) }}</span>
</MenuItem>
<Submenu v-if="item.children.length > 0&&!item.meta.hidden" :name="item.name" :key="item.name">
<template slot="title">
<i class="iconfont" v-html="item.icon"></i>
<span >{{ itemTitle(item) }}</span>
</template>
<template v-for="child in item.children">
<MenuItem v-if="!hasChildren(child)&&!child.meta.hidden" :name="child.name" :key="child.name">
<i class="iconfont" v-html="child.icon"></i>
<span> {{L(child.meta.title) }}</span>
</MenuItem>
<Submenu v-if="hasChildren(child)&&!child.meta.hidden" :name="child.name" :key="child.name">
<template slot="title">
<i class="iconfont" v-html="child.icon"></i>
<span >{{ itemTitle(child) }}</span>
</template>
<template v-for="ss in child.children">
<MenuItem v-if="!hasChildren(ss)&&!ss.meta.hidden" :name="ss.name" :key="ss.name">
<i class="iconfont" v-html="ss.icon"></i>
<span> {{L(ss.meta.title) }}</span>
</MenuItem>
</template>
</Submenu>
</template>
</Submenu>
</template>
</Menu>
</template>
<script lang="ts">
hasChildren(item:any){
return !!item.children&&item.children.length>0
}
getChildren(item:any){
return item.children;
}
</script>
修改显示路由方法
就是显示图上这个
这个方法在lib->util.ts文件中,我是抄的Vue iview-admin模板二级菜单改为三级菜单,根据abp做了一些调整,修改setCurrentPath方法如下:
setCurrentPath(vm: Vue, name?: string) {
let title = "";
let isOtherRouter = false;
vm.$store.state.app.routers.forEach(item => {
if (item.children.length === 1) {
if (item.children[0].name === name) {
title = util.handleTitle(vm, item);
if (item.name === "otherRouter") {
isOtherRouter = true;
}
}
} else {
item.children.forEach(child => {
if (child.name === name) {
title = util.handleTitle(vm, child);
if (item.name === "otherRouter") {
isOtherRouter = true;
}
}
});
}
});
let currentPathArr = [];
//去首页
if (name === "home_index") {
currentPathArr = [
{
meta: {title: util.handleTitle(
vm,
util.getRouterObjByName(vm.$store.state.app.routers, "home_index")
)},
path: "",
name: "home_index"
}
];
}
//去导航菜单一级页面或者OtherRouter路由中的页面
else if (
(name.indexOf("_index") >= 0 || isOtherRouter) &&
name !== "home_index"
) {
currentPathArr = [
{
meta: {title: util.handleTitle(
vm,
util.getRouterObjByName(vm.$store.state.app.routers, "home_index")
)},
path: "/home",
name: "home_index"
},
{
meta: {title: title},
path: "",
name: name
}
];
}
//去导航菜单二级页面或三级页面
else {
let currentPathObj = vm.$store.state.app.routers.filter(item => {
var hasMenu;
if (item.children.length <= 1) {
hasMenu = item.children[0].name === name;
return hasMenu;
} else {
let i = 0;
let childArr = item.children;
let len = childArr.length;
while (i < len) {
//如果是三级页面按钮,则在二级按钮数组中找不到这个按钮名称
//需要二级页面下可能出现三级子菜单的情况逻辑加入
if (childArr[i].name === name) {
hasMenu = true;
return hasMenu;
}
i++;
}
//如果一级,二级菜单下都没有此按钮名称,则遍历三级菜单
if (!hasMenu) {
for (let m = 0; m < childArr.length; m++) {
if (!childArr[m].children) continue;
let sonArr = childArr[m].children;
for (let n = 0; n < sonArr.length; n++) {
if (sonArr[n].name === name) {
hasMenu = true;
return hasMenu;
}
}
}
}
return false;
}
})[0];
if (
currentPathObj.children.length <= 1 &&
currentPathObj.name === "home"
) {
currentPathArr = [
{
meta: { title: "HomePage" },
path: "main/home",
name: "home"
}
];
} else if (
currentPathObj.children.length <= 1 &&
currentPathObj.name !== "home"
) {
currentPathArr = [
{
meta: { title: "HomePage" },
path: "main/home",
name: "home"
},
{
meta: {title: currentPathObj.meta.title},
path: "",
name: name
}
];
} else {
//如果是三级页面按钮,则在二级按钮数组中找不到这个按钮名称
//需要二级页面下可能出现三级子菜单的情况逻辑加入
let childObj = currentPathObj.children.filter(child => {
return child.name === name;
})[0];
//二级页面
if (childObj) {
currentPathArr = [
{
meta: { title: "HomePage" },
path: "main/home",
name: "home"
},
{
meta: {title: currentPathObj.meta.title},
path: "",
name: ""
},
{
meta: {title: childObj.meta.title},
path: currentPathObj.path + "/" + childObj.path,
name: name
}
];
}
//childobj为undefined,再从三级页面中遍历
else {
let thirdObj;
let childObj = currentPathObj.children.filter(child => {
let hasChildren;
hasChildren = child.name === name;
if (hasChildren) return hasChildren;
if (child.children) {
let sonArr = child.children;
for (let n = 0; n < sonArr.length; n++) {
if (sonArr[n].name === name) {
thirdObj = sonArr[n];
hasChildren = true;
return hasChildren;
}
}
}
return hasChildren;
})[0];
if (thirdObj && childObj) {
currentPathArr = [
{
meta: { title: "HomePage" },
path: "main/home",
name: "home"
},
{
meta: {title: currentPathObj.meta.title},
path: "",
name: ""
},
{
meta: {title: childObj.meta.title},
path: "", //设为空是因为此二级菜单没有实际页面且用于面包屑组件显示,path为空的将不可单击
name: ""
},
{
meta: {title: thirdObj.meta.title},
path:
currentPathObj.path +
"/" +
childObj.path +
"/" +
thirdObj.path,
name: thirdObj.name
}
];
}
}
}
}
vm.$store.commit("app/setCurrentPath", currentPathArr);
return currentPathArr;
}
修改根据菜单权限加载菜单
如果不修改加载权限,则第三级菜单无法用权限控制,第二级菜单也必须定义权限才能显示。如果第二级菜单只是目录,第三级菜单都没有权限,那么第二级目录是不应该显示出来的。
在store->modules->app.ts中修改updateMenulist方法如下:
updateMenulist(state: AppState) {
let menuList: Array<Router> = [];
[...appRouters,...organizeRouters,...labRouters,...labcheckRouters,
...devRouters,...labreportRouters,...appraiseRouters].forEach((item, index) => {
if (item.permission !== undefined) {
Util.addHasPermissionChileMenu(item);
if(item.children&&item.children.length>0){
menuList.push(item);
}
// let hasPermissionMenuArr: Array<Router> = [];
// hasPermissionMenuArr = item.children.filter(child => {
// if (child.permission !== undefined) {
// if (Util.abp.auth.hasPermission(child.permission)) {
// return child;
// }
// } else {
// return child;
// }
// });
// if (hasPermissionMenuArr.length > 0) {
// item.children = hasPermissionMenuArr;
// menuList.push(item);
// }
} else {
if (item.children.length === 1) {
menuList.push(item);
} else {
let len = menuList.push(item);
let childrenArr = [];
childrenArr = item.children.filter(child => {
return child;
});
let handledItem = JSON.parse(JSON.stringify(menuList[len - 1]));
handledItem.children = childrenArr;
menuList.splice(len - 1, 1, handledItem);
}
}
});
state.menuList = menuList;
}
在lib->util文件中,增加方法如下:
addHasPermissionChileMenu(item:any){
let that=this;
let hasPermissionMenuArr: Array<Router> = [];
if(!item.children){
return;
}
hasPermissionMenuArr = item.children.filter(child => {
let isFather=!!child.children;
that.addHasPermissionChileMenu(child);
let hasChildren=!!child.children
if (isFather&&!hasChildren) {
return false;
}
if (child.permission !== undefined) {
if (that.abp.auth.hasPermission(child.permission)) {
return child;
}
} else {
return child;
}
});
if (hasPermissionMenuArr.length > 0) {
item.children = hasPermissionMenuArr;
}else{
item.children=null;
}
}
增加三级菜单路由
在component目录中增加一个显示三级菜单内容的容器three-leve-container.vue
<template>
<div>
<router-view></router-view>
</div>
</template>
<script lang="ts">
import { Component, Vue, Inject } from "vue-property-decorator";
import ViewUI from "view-design";
import AbpBase from "../lib/abpbase";
import util from "../lib/util";
@Component({
components: {}
})
export default class ThreeLeveContainer extends AbpBase {
}
</script>
<style>
</style>
现在可以修改你的菜单定义,在二级菜单下像第一级菜单下增加二级菜单一样增加三级菜单了,二级菜单的权限可以是undefined,二级菜单的component要定义成刚才增加的路由组件,这样不需要在后端定义具体的权限,自动根据三级菜单的权限决定是否显示二级菜单。
{
path: "/menu1",
name: "menu1",
permission: "",
meta: { title: "menu1" },
icon: "",
component: main,
children: [
{
path: "menu2",
permission: undefined,
meta: { title: "menu2" },
name: "menu2",
component:() => import("../components/three-leve-container.vue"),
children: [
{
path: "menu3",
permission: "menu3",
meta: { title: "menu3" },
name: "menu3",
component: () =>
import("../views/xxxx.vue")
}
]
}]
}
参考资料