vue 动态显示三级路由

无需 vuex、本地存储实现动态显示三级路由。

目录

一、需求描述: 

二、代码

2.1 路由配置

1. 我的一级菜单和二级菜单的路由配置的:

2. 三级菜单的路由配置:

3. 上面有几个变量和要注意的细节:

2.2 封装导航栏

2.3 封装面包屑

2.4 页面布局


一、需求描述: 

   之前写过一个 element实现动态路由+面包屑,这个需求是嵌套的页面层级太多了,需要在页面中点击某个按钮,跳转到下一个页面(即该页面的子页面),在下一个页面的面包屑中显示所有前一级的路由。面包屑显示关系为:组先 - 父页面 - 当前页面。

   现在这个需求是:已确定路由中包含3级菜单,如果有3级菜单,在点击二级菜单的时候,在面包屑中将该二级菜单下所有的3级菜单都显示出来;如果是一级菜单没有子菜单,或者只有二级菜单,那么面包屑中就显示一级菜单名称或二级菜单名称。如下图:

( 上面图2中,“一级标题3”下应该是“二级标题3-1”,不小心写错了)

二、代码

  由于项目周期比较紧,代码一切从简。

2.1 路由配置

这里分布例举一下我的一级菜单、二级菜单和三级菜单的路由配置,具体 path、name、meta.title、meta.icon、component、redirect 等值需要自己去设置。

1. 我的一级菜单和二级菜单的路由配置的:

{path: '/menu4',name: 'userRoleManage',meta: {title: "一级标题4", leaf: true, hidden: false,icon:"my-icon-labelManage"},component: () => import('@/components/myLayout'),redirect: "/menu4/menu41",children:[{path: 'menu41',name: 'menu41',meta: {title: "一级标题4", hidden: false},component: () => import('@/views/menu4/menu41.vue')}]
},
{path: '/outWh',name: 'outWh',meta: {title: "一级标题3", leaf: false, hidden: false, icon: 'my-icon-packProduct'},component: () => import('@/components/myLayout'),redirect: "/outWh/list",children:[{path: 'list',name: 'list',meta: {title: "二级标题3-1", hidden: false},component: () => import('@/views/outWh/list.vue')},    {path: 'codeInfo',name: 'codeInfo',meta: {title: "二级标题3-2", hidden: false},component: () => import('@/views/outWh/codeInfo.vue')}]
}

2. 三级菜单的路由配置:

{path: '/basicData',name: 'basicData',meta: {title: "一级标题1", leaf: false, hidden: false,icon:"my-icon-labelManage"},component: () => import('@/components/myLayout'), //组件-封装好的头部、导航等页面整体框架redirect: "/basicData/goodsInfo",children:[{path: 'goodsInfo',name: 'goodsInfo',meta: {title: "二级标题1-1", hidden: false},component: () => import('@/views/basicData/goodsInfo.vue')},{path: 'warehouseInfo',name: 'warehouseInfo',meta: {title: "二级标题1-2", hidden: false, threeMenu: true},component: () => import('@/components/myLayout/breadcrumb'), //引入面包屑组件redirect: "/basicData/warehouseInfo/warehouse",children: [{path: 'warehouse',name: 'warehouse',meta: {title: "三级标题1-2-1", hidden: false},component: () => import('@/views/basicData/warehouse.vue')},{path: 'goodsShelf',name: 'goodsShelf',meta: {title: "三级标题1-2-2", hidden: false},component: () => import('@/views/basicData/goodsShelf.vue')},{path: 'goodsPlace',name: 'goodsPlace',meta: {title: "三级标题1-2-4", hidden: false},component: () => import('@/views/basicData/goodsPlace.vue')}]},{path: 'supplier',name: 'supplier',meta: {title: "二级标题1-3", hidden: false},component: () => import('@/views/basicData/supplier.vue')},{path: 'clientInfo',name: 'clientInfo',meta: {title: "二级标题1-4", hidden: false},component: () => import('@/views/basicData/clientInfo.vue')}]
}

3. 上面有几个变量和要注意的细节:

  1. leaf 表示一级菜单下是否有子菜单【在一级菜单的 meta 中书写该变量】。true:只有一级菜单,没有子菜单;false:有子菜单(有二级菜单、三级菜单都是 false);
  2. hidden :该路由配置的信息是否要在导航栏中隐藏起来。true:在导航栏上隐藏起来(即不显示),false:不隐藏(即显示)。
  3. threeMenu:是否有三级菜单【在二级菜单的 meta 中书写该变量】。true:该二级菜单下有 3 级菜单,false:该二级菜单下没有 3 级菜单。
  4. 当有 3 级菜单时,就把该 3 级菜单的二级菜单当做 一级菜单 来设置,在二级菜单中添加 componentredirect 方法。component 指向组件,redirect 重定向到页面。
  5. 有 3 级菜单时,就给该 3 级菜单的二级菜单设置:threeMenu:true,没有的可以不设置。要是想要代码统一,就在所有二级菜单中的 meta 中设置一下。

具体一些的,我在 手把手教你用 element 实现导航栏 这篇文章中有介绍。

2.2 封装导航栏

导航栏的封装我直接拿的 手把手教你用 element 实现导航栏 中的代码。

<template><el-menu id="myAside"router:default-active="$route.matched[1].path"active-text-color="#00BF9F"><!-- 侧导航栏 -->      <template v-for="(item,itemId) in allRouter"><!-- 节点不隐藏 --><template v-if="!item.meta.hidden"><!-- 是否只有一个节点 leaf:true-是只有一个节点 --><template v-if="item.meta.leaf"><el-menu-item :index="item.redirect" :key="itemId" class="oneLeaf"><i :class="item.meta.icon"></i><span slot="title" class="oneLeftTitle">{{item.meta.title}}</span></el-menu-item></template><!-- 多个节点 --><el-submenu v-else :index="item.redirect" :key="itemId"><template slot="title"><i :class="item.meta.icon"></i><span>{{item.meta.title}}</span></template><el-menu-item-group><template v-for="(child,childId) in item.children">       <template>                  <el-menu-item :index="item.path +'/'+ child.path" :key="childId" v-if="!child.meta.hidden">{{child.meta.title}}</el-menu-item>  </template><!-- 判断是否为3级菜单结束--></template></el-menu-item-group></el-submenu></template></template></el-menu>
</template><script>
// import { mapGetters } from "vuex";export default {data(){return {allRouter: this.$router.options.routes}}
}
</script><style scoped lang="scss">
#myAside{border-right:0;.my-icon-labelManage{display: inline-block;width:20px;height:20px;}.my-icon-labelManage{background: url("~@/assets/menu/labelInit.png") center no-repeat;}.my-icon-labelManage:before{content: "\8d3a";font-size: 22px;visibility: hidden;}.el-submenu.is-active, .el-menu-item.is-active{.my-icon-labelManage{background: url("~@/assets/menu/labelInit_active.png") center no-repeat;}    }
}
</style>

不过这里有个细节需要注意一下:

导航栏上激活的选项(即被选中的一级菜单/二级菜单)与 :default-active 属性值有关。当我们点击三级菜单时,导航栏上被激活的是该三级菜单的二级菜单,所以 :default-active 的属性值应该是 二级菜单的 path 值,而不是 当前三级菜单的 $route.path 值。

【这里特地提一下,因为这一步我被卡了一下,三级菜单的面包屑和二级菜单的导航把我绕进去了......想一想怎么描述这个过程,还是有点晕】 

另外,:default-active="$route.matched[1].path" 这个属性值还挺神奇的,要是只有一级和二级菜单也可以用这个属性值代替,以后我写导航的激活就用这个值了嘿嘿~。(有需要的可以自己打印看看)

2.3 封装面包屑

原本我打算根据路由配置中二级菜单的 meta.threeMenu 的属性值,来判断被点击的二级菜单中有没有包含三级菜单,但是因为这是写在二级菜单里面,需要循环一下。后面发现 this.$route.matched 有个很方便的特点:

  1. 路由配置中如果一级路由下没有 children: [],那么 this.$route.matched.length = 1
  2. 路由配置中如果一级路由下有二级菜单,写了一个 children,那么 this.$route.matched.length = 2
  3. 路由配置中如果二级路由下有三级菜单,又写了一个 children,那么 this.$route.matched.length = 3

 总的来说:路由配置中一级菜单下总共包含了几个children,那么 this.$route.matched 的长度 = children数量 + 1。 利用这个特点,就能很方便快速的判断出点击的一级/二级菜单下是否有三级菜单。

 思路:

1. 判断点击的路由是否包含3级菜单。

        由于我配置路由时,没有二级菜单的一级菜单有二级菜单的一级菜单 是根据 leaf 值来判断的,两者都写了 children:[],所以 this.$route.matched.length 都= 2。但是不管是前者还是后者,被点击时,面包屑中显示的都是被点击的那个路由信息(即1级菜单面包屑显示1级菜单名称,2级菜单面包屑显示2级菜单名称)。

2. 如果没有 3级菜单( 即 this.$route.matched.length = 2),就把当前点击的路由信息保存下来。

3. 如果有 3级菜单,那么点击二级菜单时,就要把该二级菜单下的所有 3级菜单的路由信息保存下来。

4. 将保存下来的路由信息在面包屑中显示出来,这里用到 router-link,3级菜单被选中激活时,router-link 会自动生成一个 .router-link-active 的 class 名。

<template><div id="breadcrumb"><!-- 面包屑 --><div class="bg pd20 clear mb20"><router-link v-for="three in threeRouters" :key="three.name" :to="three.path">{{three.meta.title}}</router-link></div><router-view v-if="threeMenuOff"></router-view></div>
</template><script>
export default {data(){return {allRouter: this.$router.options.routes, //获取所有菜单threeRouters: [],threeMenuOff: false}},watch: {"$route": {handler(val,oldval){// console.log("面包屑监听",val, oldval)this.getChildRoute(val)},deep: true,immediate: true}},methods:{getChildRoute(currRoute){console.log("breadcrumb",currRoute,this.allRouter)if(currRoute.matched.length == 2){this.threeRouters = [currRoute]; //直接将当前的路由信息传给组件this.threeMenuOff = false;}else if(currRoute.matched.length == 3){ //说明有3级路由this.allRouter.map(item=>{if(currRoute.matched[0].path == item.path){//二级路由。存所有三级路由的数据item.children.map(child =>{if(currRoute.matched[1].name == child.name){this.threeRouters = JSON.parse(JSON.stringify(child.children));}});}})this.threeMenuOff = true;} //判断结束currRoute.matched.length=3console.log("3ji菜单",this.threeRouters)} ,},
}
</script><style lang="scss" scoped>
#breadcrumb{margin-bottom: 20px;a{float: left;margin-right: 20px;}a.router-link-active{border-bottom:2px solid #f88;}
}
</style>

这里需要注意:三级路由的页面,需要添加 <router-view></roter-view>,否则三级页面显示空白。原因是在配置时,二级路由的 component 指向的是面包屑组件路径而非三级页面所在路径,通过 redirect 重定向到三级页面。

2.4 页面布局

这个部分因为有个需要注意的地方,所以也贴一下代码。

<template><el-container><el-header class="bg" style="height: 80px;"> <v-head></v-head> </el-header><el-container><el-aside width="260px" class="bg"> <my-aside></my-aside> </el-aside><el-main><breadcrumb v-if="!threeMenuOff"></breadcrumb><router-view></router-view></el-main></el-container></el-container>
</template><script>
import vHead from "./vHead"
import myAside from "./myAside"
import breadcrumb from "./breadcrumb"
export default {components: { vHead, myAside, breadcrumb },data(){return {threeMenuOff: false  //3级菜单的不需要面包屑组件,因为在路由中components已经配置了}},watch: {"$route": {handler(val,oldval){console.log("myLayout",val)if(val.matched.length == 3 || val.name == "home"){this.threeMenuOff = true; //不需要面包屑组件,将threeMenuOff = true} else {this.threeMenuOff = false;}},deep: true,immediate: true}},
}
</script>

    这里在原来的布局上添加了 <breadcrumb></bredcrumb> 组件,前面在路由配置中,配置了3级菜单的面包屑,这里添加 breadcrumb 组件是给1级菜单和2级菜单添加面包屑的。同时,通常 首页home 是不需要面包屑的,这里也可以做判断,控制面包屑的显示和隐藏。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362421.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第二章 Vue快速入门-- 18 v-for中key的使用注意事项

注意:如果属性和方法还没定义直接使用的话&#xff0c;就会报 xxx is not defined 导致界面不能正常显示。我看视频教程里老师的可以直接使用&#xff0c;而且界面正常显示&#xff0c;可能是vue版本不同吗&#xff1f;还不清楚 1 <!DOCTYPE html>2 <html lang"…

口碑网发布2010吃住玩消费风向指数

当在淘宝网上买衣服、买电器、买……都变得司空见惯&#xff0c;下一步我们会在网上完成什么消费&#xff1f; 通过网购等电子商务模式的带动&#xff0c;电子商务平台对于老百姓日常消费、生活的影响逐渐深化。原本更多依靠传统手段完成的吃住玩等生活消费&#xff0c;现在也…

Java并发教程–线程安全设计

在回顾了处理并发程序时的主要风险&#xff08;如原子性或可见性 &#xff09;之后&#xff0c;我们将进行一些类设计&#xff0c;以帮助我们防止上述错误。 其中一些设计导致了线程安全对象的构造&#xff0c;从而使我们可以在线程之间安全地共享它们。 作为示例&#xff0c;我…

ES6 iterator 迭代器

iterator使用TypeScript 的描述&#xff1a; interface Iterable {[Symbol.iterator]() : Iterator,}interface Iterator {next(value?: any) : IterationResult,}interface IterationResult {value: any,done: boolean,} 一个数据结构只要具有 Symbol.iterator属性&#xff0…

vue 后端返回二进制流文件,前端如何实现下载?

目录 1. axios 请求二进制流文件导出文件 1.1 后台返回的二进制流&#xff1a; 1.2 使用&#xff1a; 1.3 需要注意以下几点&#xff1a; 2. 关于 arraybuffer 和 blob 2.1 ArrayBuffer 和 blob 2.2 区别 2.3 相互转换 3. 主要参考&#xff1a; 1. axios 请求二进制…

python量化之路:获取历史某一时刻沪深上市公司股票代码及上市时间

python量化之路&#xff1a;获取历史某一时刻沪深上市公司股票代码及上市时间 最近开始玩股票量化&#xff0c;由于想要做完整的股票回测&#xff0c;因此股票的上市和退市信息就必不可少。因为我们回测的时候必须要知道某一日期沪深股票的成分包含哪些对吧。所以我们要把沪深全…

《网页设计创意书》读后感

刚刚收到《网页设计创意书》&#xff0c;确实有点惊喜&#xff0c;开始以为是像之前审读的书一样是一叠叠的打印纸&#xff0c;没想到是一本成品书&#xff0c;拿到手上沉甸甸的&#xff0c;随便翻看了一下&#xff0c;没想到里面竟然还是全彩页印刷的&#xff0c;本书的第一感…

游戏AI –行为树简介

游戏AI是一个非常广泛的主题&#xff0c;尽管有很多资料&#xff0c;但我找不到能以较慢&#xff0c;更容易理解的速度缓慢介绍这些概念的东西。 本文将尝试解释如何基于行为树的概念来设计一个非常简单但可扩展的AI系统。 什么是AI&#xff1f; 人工智能是参与游戏的实体表现…

js 常用类型转换简写

1、字符串转数字 666// 666 2、转换为字符串 666//666 更多专业前端知识&#xff0c;请上 【猿2048】www.mk2048.com

mockJs文档(二)

mockJs官方文档 mockJs文档&#xff08;一&#xff09; 目录 1. Mock.mock( rurl?, rtype?, template|function( options ) ) 1.1 Mock.mock( template ) 1.2 Mock.mock( rurl, template ) 1.3 Mock.mock( rurl, function( options ) ) 1.4 Mock.mock( rurl, r…

winforms中限定上传文件类型

获取文件路径string fileExtension System.IO.Path.GetExtension(filePath).ToLower();bool flag true;string[] AllowExtension { ".doc", ".xls", ".ppt", ".docx", ".xlsx", ".pptx", ".txt", &q…

liteos错误处理(十一)

1. 概述 1.1 基本概念 错误处理指用户代码发生错误时&#xff0c;系统调用错误处理模块的接口函数&#xff0c;完成上报错误信息&#xff0c;并调用用户自己的钩子函数&#xff0c;进行特定的处理。 错误处理模块实现OS内部错误码记录功能。OS内部错误码无法通过接口返回&#…

这是东西:jUnit:动态测试生成

当您需要在许多不同的输入值或配置上运行同一组测试时&#xff0c;动态测试生成很有用。 可以使用参数化测试或使用理论来实现。 当您有大量数据用作参数并想对所有组合进行测试时&#xff0c;这些理论非常有用。 您得到的控制较少&#xff0c;但是您不必自己编写合并和迭代的…

js 变量提升与函数提升

规则&#xff1a; 函数的提升优先于变量提升。同名的函数会覆盖同名的函数与变量。同名的变量不会覆盖同名的函数。 示例代码1&#xff1a; <!DOCTYPE html><html lang"zh"><head><meta charset"UTF-8" /><meta name"vi…

mockJs文档(一)

Mock.js 官网 目录 1. 开始安装 1.1 Node&#xff08;CommonJS&#xff09; 1.2 CMD方式 2. 语法规范 2.1 数据模板定义规范 DTD 2.1.1. 属性值是字符串 String 2.1.2. 属性值是数字 Number 2.1.3. 属性值是布尔型 Boolean 2.1.4. 属性值是对象 Object 2.1.5. 属性值…

【JOURNAL】《不思八九》 --和友腊八诗一首

不思八九旧岁新醅雪&#xff0c;腊八数九粥。红泥杜康曲&#xff0c;暖腹亦无忧。&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;http://t.sina.com.cn/n/博客顺风 腊八 辞岁逢新雪&#xff0c;好煮腊八粥。且将情入味&#xff0c;一并…

团队测试计划

我们是否需要测试&#xff0c;直到我们的软件是完美的&#xff1f; 首先针对第一个问题&#xff0c;我们一直觉得有必要&#xff0c;因为老师说过&#xff0c;只有多次测试才能真正检测出自己的代码是否完全没问题&#xff0c;所以我们进行了多次测试&#xff0c;虽然我对自己的…

ChoiceFormat:数字范围格式

ChoiceFormat类的Javadoc声明ChoiceFormat “允许您将格式附加到一定范围的数字上”&#xff0c;并且“通常在MessageFormat中用于处理复数”。 这篇文章描述了java.text.ChoiceFormat并提供了一些在Java代码中应用它的示例。 ChoiceFormat与java.text包中其他“ 格式 ”类之间…

vue sync用法

1、父组件 <add-rule :show.sync"showEditDialog" :addOrUpdate"addOrUpdate" close"showEditDialog false" :ruleData"editIfo" /> 2、子组件 // 这样可以// this.$emit(close)// 这样也可以this.$emit(update:show, false);…

小程序 获取手机号

【参考小程序开发文档&#xff1a;开发-指南-开放能力-用户信息-获取手机号】 地理位置 wx.getLocation(Object object) | 微信开放文档 手机号 获取手机号 | 微信开放文档 微信信息 小程序与小游戏获取用户信息接口调整&#xff0c;请开发者注意升级。 | 微信开放社区 目录…