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

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&&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;

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

ABP实践(5)-abp前端vue框架之IView实现三级菜单(博友需要特此分享)的更多相关文章

  1. ABP实践(4)-abp前端vue框架之简单商品增删改查(帮助刚入门的新手快速了解怎么才能加入自己的功能并运行起来)

    提示:如有不明白的地方请先查看前3篇ABP实践系列的文章 1,下载及启动abp项目前后端分离(netcore+vue) 2,修改abp数据库为mysql 3,商品系列api接口(本文主要依赖在这个商品 ...

  2. 前端vue框架 脚手架

    1.安装node.js最新版本2.cmd下输入 1.node -v得到版本号检测是否安装成功 版本号要在6.9以上 2.npm -v 版本号要在3.10以上3.安装脚手架 1.npm install ...

  3. vue的递归组件以及三级菜单的制作

    js里面有递归算法,同时,我们也可以利用props来实现vue模板的递归调用,但是前提是组件拥有 name 属性 父组件:slotDemo.vue: <template> <div& ...

  4. 前端--vue框架

    1.下载 查看已安装好的版本 -------渐进式的JS框架--------- vue是什么 Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的 渐进式框架.与其他重量级框架 ...

  5. 前端VUE框架

    一.什么是VUE?  它是一个构建用户界面的JAVASCRIPt框架  vue不关心你页面上的是什么标签,它操作的是变量或属性 为什么要使用VUE? 在前后端分离的时候,后端只返回json数据,再没有 ...

  6. 前端vue框架上手记录

    ---恢复内容开始--- Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,提供: 通过 @vue/cli 搭建交互式的项目脚手架. 通过 @vue/cli + @vue/cli-se ...

  7. 前端vue框架 路由的安装及使用

    安装: 1.cmd下输入: npm install vue-router --save //安装路由 2.npm run dev //重新启动 使用: 1.在mian.js下引入路由 import V ...

  8. 前端Vue框架-vuex状态管理详解

    新人报道!多多关照-多提宝贵意见 谢谢- vuex理解 采用集中式存储管理模式.用来管理组件的状态,并以自定义规则去观测实时监听值得变化. 状态模式管理理解 属性 理解 state 驱动应用的数据源 ...

  9. 前端vue框架 父组件与子组件之间的相互调用

    子组件调用父组件东西: 1.在父组件与子组件契合的标签的的template模板中绑定 v-bind:自定义一个名字=“要调用的名字” 2.在子组件的script中props:["自定义的名字 ...

  10. 前端VUE框架-es6

    EMCAScript 6 又叫 es2015 1.常量和变量 常量: const a = "hello" 常量不能修改和重复定义 变量: let:定义一个块级作用域的变量 需要先定 ...

随机推荐

  1. C 语言编译过程

    编译过程 编译过程是将高级编程语言(如 C 语言)写成的源代码转换成机器可以执行的低级机器语言(通常是二进制代码)的过程.这个过程一般可以分为几个阶段: 预处理(Preprocessing): 预处理 ...

  2. vue serve 部署 步骤说明

    1. 构建镜像 docker build -t 镜像名称:镜像TAG --build-arg URL=http://localhost:8081 --build-arg PORT=2000 --bui ...

  3. react + vite

    Vite 和 Yarn都比较新的技术 Ref: https://www.digitalocean.com/community/tutorials/how-to-set-up-a-react-proje ...

  4. .NET 8 + WPF 企业级工作流系统

    前言 推荐一款基于.NET 8.WPF.Prism.DryIoc.MVVM设计模式.Blazor以及MySQL数据库构建的企业级工作流系统的WPF客户端框架-AIStudio.Wpf.AClient ...

  5. 总结篇4:redis 核心数据存储结构及核心业务模型实现应用场景

    总结篇4:redis 核心数据存储结构及核心业务模型实现应用场景 redis 和memcached 有什么区别?为什么在高并发下,单线程的redis 比多线程的效率高? mc 可以缓存图片和视频,re ...

  6. c程序设计语言 by K&R(一)一些c语言基础知识

    出自<c程序设计语言> by K&R: 一.导言 二.类型.运算符与表达式 三.控制流 1. 字符输入与输出 getchar() 和 putchar(),输入一个字符.输出一个字符 ...

  7. 英文短语和单词备忘 - as well as

    English phrases and vocabulary notes: as well as "as well as" 是一个连接词组,通常用于连接两个相似的元素,以强调两者都 ...

  8. OData – Get Started 搭建单侧环境

    前言 之前写过 EF Core – Get Started 搭建单侧环境, 这篇补上一个 WebApi + EF Core + OData 创建项目 dotnet new webapi -o EfCo ...

  9. Figma 学习笔记 – Component

    参考 Guide to Components in Figma Figma Tutorial: Components - The Basics (Youtube) 定义与用途 Figma 的 Comp ...

  10. Figma 学习笔记 – Auto Layout

    用途 Auto Layout 有点像 CSS 的 Flex, 它还带有 responsive 的概念.使用它以后可以替代掉不少 constraints 的写法. 用法 一个 parent 抱着多个 c ...