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. 上面有幾個變量和要注意的細節:
具體一些的,我在?手把手教你用 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 有個很方便的特點:
?總的來說:路由配置中一級菜單下總共包含了幾個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 是不需要面包屑的,這里也可以做判斷,控制面包屑的顯示和隱藏。
總結
以上是生活随笔為你收集整理的vue 动态显示三级路由的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小程序 报错errMsg: “hideL
- 下一篇: vue 后端返回二进制流文件,前端如何实