ABP实践(5)-abp前端vue框架之IView实现三级菜单(博友需要特此分享)
为响应博友想要知道三级菜单怎么实现本篇文章先介绍三级菜单的实现,后续再分享其他部分内容
1 修改菜单组件sidebarMenu.vue
- 图为原代码和修改后代码比对
- 修改前后的源码如下
<style lang="less">
@import "../styles/menu.less";
</style>
<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" :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 :name="child.name" :key="child.name">
<i class="iconfont" v-html="child.icon"></i>
<span>{{ L(child.meta.title) }}</span>
</MenuItem>
</template>
</Submenu>-->
<Submenu v-if="item.children.length > 0" :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="!isChild(child.children)" :name="child.name" :key="child.name">
<i class="iconfont" v-html="child.icon"></i>
<span>{{ L(child.meta.title) }}</span>
</MenuItem>
<Submenu v-else :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="child in child.children">
<MenuItem v-if="!isChild(child.children)" :name="child.name" :key="child.name">
<i class="iconfont" v-html="child.icon"></i>
<span>{{ L(child.meta.title) }}</span>
</MenuItem>
</template>
</Submenu>
</template>
</Submenu>
</template>
</Menu>
</template>
<script lang="ts">
import { Component, Vue, Inject, Prop, Emit } from "vue-property-decorator";
import AbpBase from "../../../lib/abpbase";
@Component({})
export default class SidebarMenu extends AbpBase {
name: string = "sidebarMenu";
@Prop({ type: Array }) menuList: Array<any>;
@Prop({ type: Number }) iconSize: number;
@Prop({ type: String, default: "dark" }) menuTheme: string;
@Prop({ type: Array }) openNames: Array<string>;
itemTitle(item: any): string {
return this.L(item.meta.title);
}
@Emit("on-change")
changeMenu(active: string) {}
updated() {
this.$nextTick(() => {
if (this.$refs.sideMenu) {
(this.$refs.sideMenu as any).updateActiveName();
}
});
}
isChild(item) {
if (item && item.length > 0) {
return true;
} else {
return false;
}
}
}
</script>
2 修改路由菜单配置文件router.ts
- 在新增的内容里有注释(第三级菜单),全部代码如下
declare global {
interface RouterMeta {
title: string;
}
interface Router {
path: string;
name: string;
icon?: string;
permission?: string;
meta?: RouterMeta;
component: any;
children?: Array<Router>;
}
interface System {
import(request: string): Promise<any>
}
var System: System
}
import login from '../views/login.vue'
import home from '../views/home/home.vue'
import main from '../views/main.vue'
export const locking = {
path: '/locking',
name: 'locking',
component: () => import('../components/lockscreen/components/locking-page.vue')
};
export const loginRouter: Router = {
path: '/',
name: 'login',
meta: {
title: 'LogIn'
},
component: () => import('../views/login.vue')
};
export const otherRouters: Router = {
path: '/main',
name: 'main',
permission: '',
meta: { title: 'ManageMenu' },
component: main,
children: [
{ path: 'home', meta: { title: 'HomePage' }, name: 'home', component: () => import('../views/home/home.vue') }
]
}
export const appRouters: Array<Router> = [{
path: '/setting',
name: 'setting',
permission: '',
meta: { title: 'ManageMenu' },
icon: '',
component: main,
children: [
{ path: 'user', permission: 'Pages.Users', meta: { title: 'Users' }, name: 'user', component: () => import('../views/setting/user/user.vue') },
{ path: 'role', permission: 'Pages.Roles', meta: { title: 'Roles' }, name: 'role', component: () => import('../views/setting/role/role.vue') },
{ path: 'tenant', permission: 'Pages.Tenants', meta: { title: 'Tenants' }, name: 'tenant', component: () => import('../views/setting/tenant/tenant.vue') },
{ path: 'goods', permission: 'Pages.Goods', meta: { title: 'Goods' }, name: 'goods', component: () => import('../views/setting/goods/goods.vue') },
//第三级菜单
{
path: '', permission: 'Pages.Goods', meta: { title: 'GoodsManage' }, name: 'goodsManage', component:()=> import('../views/setting/goods/goods.vue'),
children: [
{ path: 'goods', permission: 'Pages.Goods', meta: { title: 'Goods' }, name: 'goods', component: () => import('../views/setting/goods/goods.vue') }
]
}
]
}]
export const routers = [
loginRouter,
locking,
...appRouters,
otherRouters
];
到此菜单已经可以出来,但是头部面包屑展示有问题需要修改lib下的util.ts改后代码如下其中有注释面包屑字眼的为修改代码
import Vue from 'vue';
import appconst from './appconst'
class Util{
abp:any=window.abp;
loadScript(url:string){
var script=document.createElement('script');
script.type="text/javascript";
script.src=url;
document.body.appendChild(script);
}
title(title:string){
let appname=this.abp.localization.localize('AppName',appconst.localization.defaultLocalizationSourceName);
let page=this.abp.localization.localize(title,appconst.localization.defaultLocalizationSourceName);
window.document.title = appname+'--'+page;
}
inOf(arr:Array<any>, targetArr:any) {
let res = true;
arr.forEach(item => {
if (targetArr.indexOf(item) < 0) {
res = false;
}
});
return res;
}
oneOf(ele:any, targetArr:Array<any>) {
if (targetArr.indexOf(ele) >= 0) {
return true;
} else {
return false;
}
}
showThisRoute (itAccess:any, currentAccess:any) {
if (typeof itAccess === 'object' && Array.isArray(itAccess)) {
return this.oneOf(currentAccess, itAccess);
} else {
return itAccess === currentAccess;
}
}
getRouterObjByName (routers:Array<any>, name?:string):any {
if (!name || !routers || !routers.length) {
return null;
}
let routerObj = null;
for (let item of routers) {
if (item.name === name) {
return item;
}
routerObj = this.getRouterObjByName(item.children, name);
if (routerObj) {
return routerObj;
}
}
return null;
}
toDefaultPage (routers:Array<any>, name:string|undefined, route:any, next:any) {
let len = routers.length;
let i = 0;
let notHandle = true;
while (i < len) {
if (routers[i].name === name && routers[i].children && routers[i].redirect === undefined) {
route.replace({
name: routers[i].children[0].name
});
notHandle = false;
next();
break;
}
i++;
}
if (notHandle) {
next();
}
}
handleTitle (vm:any, item:any) {
if (typeof item.meta.title === 'object') {
return vm.$t(item.title.i18n);
} else {
return item.meta.title;
}
}
setCurrentPath (vm:Vue, name?:string) {
let title = '';
let isOtherRouter = false;
vm.$store.state.app.routers.forEach((item:any) => {
if (item.children.length === 1) {
if (item.children[0].name === name) {
title = this.handleTitle(vm, item);
if (item.name === 'otherRouter') {
isOtherRouter = true;
}
}
} else {
item.children.forEach((child:any) => {
if (child.name === name) {
title = this.handleTitle(vm, child);
if (item.name === 'otherRouter') {
isOtherRouter = true;
}
}
});
}
});
let currentPathArr = [];
if (name === 'home') {
currentPathArr = [
{
meta:{title: this.handleTitle(vm, this.getRouterObjByName(vm.$store.state.app.routers, 'home'))},
path: 'main/home',
name: 'home'
}
];
} else if (((name as string).indexOf('index') >= 0 || isOtherRouter) && name !== 'home') {
currentPathArr = [
{
meta:{title: this.handleTitle(vm, this.getRouterObjByName(vm.$store.state.app.routers, 'home'))},
path: 'main/home',
name: 'home'
},
{
meta:{title: title},
path: '',
name: name
}
];
} else {
let currentPathObj = vm.$store.state.app.routers.filter((item:any) => {
if (item.children.length <= 1) {
return item.children[0].name === name||item.name===name;
} else {
let i = 0;
let childArr = item.children;
let len = childArr.length;
while (i < len) {
//第三级菜单面包屑
if(childArr[i].children&&childArr[i].children.length>0){
for(let children of childArr[i].children){
if(children.name===name){
return true;
}
}
}
//-------------
if (childArr[i].name === name) {
return true;
}
i++;
}
return false;
}
})[0];
if (currentPathObj.children&¤tPathObj.children.length <= 1 && currentPathObj.name === 'home') {
currentPathArr = [
{
meta:{title: 'HomePage'},
path: 'main/home',
name: 'home'
}
];
} else if (currentPathObj.children&¤tPathObj.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:any) => {
//第三级菜单实现
if(child.children&&child.children.length>0){
return true;
}
//--------------------
return child.name === name;
})[0];
currentPathArr = [
{
meta:{title: 'HomePage'},
path: 'main/home',
name: 'home'
},
{
meta:{title: currentPathObj.meta.title},
path: '',
name: ''
},
{//-----第三级菜单面包屑
meta:{title: childObj.meta.title},
path: '',
name: childObj.name
}
];
if(childObj.children&&childObj.children.length>0){
let tChildObj = childObj.children.filter((child:any) => {
return child.name === name;
})[0];
if(tChildObj){
let tr={
meta:{title: tChildObj.meta.title},
path: currentPathObj.path + '/' +tChildObj.path+'/'+ tChildObj.path,
name: name
}
currentPathArr.push(tr)
}
}
//--------------------
}
}
vm.$store.commit('app/setCurrentPath', currentPathArr);
return currentPathArr;
}
openNewPage (vm:Vue, name:string|undefined, argu?:any, query?:any) {
let pageOpenedList = vm.$store.state.app.pageOpenedList;
let openedPageLen = pageOpenedList.length;
let i = 0;
let tagHasOpened = false;
while (i < openedPageLen) {
if (name === pageOpenedList[i].name) { // 页面已经打开
vm.$store.commit('app/pageOpenedList', {
index: i,
argu: argu,
query: query
});
tagHasOpened = true;
break;
}
i++;
}
if (!tagHasOpened) {
let tag = vm.$store.state.app.tagsList.filter((item:any) => {
if (item.children) {
return name === item.children[0].name;
} else {
return name === item.name;
}
});
tag = tag[0];
if (tag) {
tag = tag.children ? tag.children[0] : tag;
if (argu) {
tag.argu = argu;
}
if (query) {
tag.query = query;
}
vm.$store.commit('app/increateTag', tag);
}
}
vm.$store.commit('app/setCurrentPageName', name);
}
fullscreenEvent (vm:Vue) {
vm.$store.commit('app/initCachepage');
// 权限菜单过滤相关
vm.$store.commit('app/updateMenulist');
// 全屏相关
}
extend(...args:any[]) {
let options, name, src, srcType, copy, copyType, copyIsArray, clone,
target = args[0] || {},
i = 1,
length = args.length,
deep = false;
if ( typeof target === 'boolean') {
deep = target;
target = args[i] || {};
i++;
}
if ( typeof target !== 'object' && typeof target !== 'function') {
target = {};
}
if ( i === length) {
target = this;
i--;
}
for ( ; i < length; i++ ) {
if ( (options = args[i]) !== null ) {
for ( name in options ) {
src = target[name];
copy = options[name];
if ( target === copy ) {
continue;
}
srcType = Array.isArray(src) ? 'array': typeof src;
if ( deep && copy && ((copyIsArray = Array.isArray(copy)) || typeof copy === 'object')) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && srcType === 'array' ? src : [];
} else {
clone = src && srcType === 'object' ? src: {};
}
target[name] = this.extend(deep, clone, copy);
} else if ( copy !== undefined ) {
target[name] = copy;
}
}
}
}
return target;
}
}
const util=new Util();
export default util;
知道如何实现三级菜单可以考虑一下怎么实现无限级菜单(以后有时间再分享)
有梦想一定要去做
但是未必一定要实现