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")
}
]
}]
}
參考資料
