首页 > 技术文章 > ABP实践(5)-abp前端vue框架之IView实现三级菜单(博友需要特此分享)

wuyubing 2020-04-01 16:44 原文

为响应博友想要知道三级菜单怎么实现本篇文章先介绍三级菜单的实现,后续再分享其他部分内容

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: '&#xe68a;',
    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&&currentPathObj.children.length <= 1 && currentPathObj.name === 'home') {
                currentPathArr = [
                    {
                        meta:{title: 'HomePage'},
                        path: 'main/home',
                        name: 'home'
                    }
                ];
            } else if (currentPathObj.children&&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: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;

知道如何实现三级菜单可以考虑一下怎么实现无限级菜单(以后有时间再分享)

推荐阅读