专栏首页小神仙Vue+abp增加三级菜单

Vue+abp增加三级菜单


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: "&#xe68a;",
    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")
        }
        ]
      }]
  }

参考资料

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • EPPlusHelper

    用户6362579
  • Linq调试实时输出信息扩展方法(摘抄)

    用户6362579
  • asp.net core导入excel

    对比昨天导出的内容增加了一行实体属性名称作为标题行,这样到转换为实体的时候才能找到对应的属性。

    用户6362579
  • Hive部署及两种启动方式

    Facebook解决海量日志数据的分析而开发了Hive,后来开源给了Apache软件基金会。

    公众号guangcity
  • Web应用程序防火墙(WAF)bypass技术讨论(一)

    Web应用程序中发现RCE漏洞的情况还是挺常见的,2017 OWASP Top 10应用程序安全风险”也将“注入”置于第一位置,例如当解释器接收到用户可控的数据...

    HACK学习
  • if判断与比较操作符gt、lt、eq等的使用

    PS:使用if判断时,需要在判断结束处填入"fi",表示if语句块的结束 例如: if [ $ACTION = "add"] then .....

    张诺谦
  • 数据分析篇(五)

    attr = pd.DataFrame(np.arange(12).reshape(3,4))

    不断折腾
  • .clearfix:after的用法,清除浮动

    deepcc
  • Sphinx源码学习笔记(一):索引创建

      因为项目开发需要在游戏内部实现玩家名称的模糊查找功能,本身直接使用Sphinx配置mysql可以直接搭建一套模糊匹配的即可支持功能的实现。

    dylan_若水
  • UNPv1第八章:基本UDP套接口编程

    使用UDP编写的一些常用应用程序有:DNS(域名系统)、NFS(网络文件系统)和SNMP(简单网络管理协议)

    刘晓杰

扫码关注云+社区

领取腾讯云代金券