介绍:目前使用的路由表是三级路由表,文章中使用Element-UI动态生成导航栏可以有N级路由嵌套,但是事实上不会有那么多级路由,但是为了方便还是一次性写好,使用时就是复制文件就好
const RouterMap =[
{ path: '/login', component: () => import('@/views/login'), hidden: true },
{
path: '/test',
component: Layout,
name: 'test',
redirect: '/test/aa'
children: [
{
path: 'aa',
component: () => import('@/views/test/aa'),
name: 'aa'
},
{
path: 'kk',
component: () => import('@/views/test/kk'),
name: 'kk'
},
{
path: 'thirt',
name: 'thirt',
component: () => import('@/views/test/thirt'),
redirect: '/test/thirt/coldd',
children: [
{
path: 'coldd',
component: () => import('@/views/test/coldd'),
name: 'coldd'
},
{
path: 'dasiaed',
component: () => import('@/views/test/dasiaed'),
name: 'dasiaed',
hidden: true
}
]
}
]
}
]
export default new Router({
routes: RouterMap
})
备注: 在使用Element-UI的NavMenu组件时,应该先查看文档说明。链接:https://element.eleme.cn/#/zh-CN/component/transition
navbar.vue文件:(default-active用于判断当前选中的menu-item)
<template>
<el-menu
mode="vertical"
:show-timeout="200"
:default-active="routePath"
:collapse="isCollapse"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
:unique-opened="true"
>
<sidebar-item :routes="permission_routers"></sidebar-item>
</el-menu>
</template>
<script>
import SidebarItem from './SidebarItem'
export default {navbar.vue
components: { SidebarItem },
computed: {
routePath() {
// this.$route.path 很长时使用正则表达式匹配
// if (this.$route.path.search('/test/thirt') !== -1) {
// return '/test/thirt/coldd'
// } else {
// return this.$route.path
// }
if (this.$route.path === '/test/thirt/coldd' || this.$route.path === '/test/thirt/dasiaed') {
return '/test/thirt/coldd'
} else {
return this.$route.path
}
}
}
}
</script>
方法一:sidebar-item.vue文件(Menu未开启router属性,使用router-link跳转。):
<template>
<div class="menu-wrapper">
<template v-for="item in routes" v-if="!item.hidden&&item.children">
<!--当路由只有一个子路由时-->
<router-link v-if="hasOneShowingChildren(item.children) && !item.children[0].children&&!item.alwaysShow" :to="parent ? parent + '/' + item.path+'/'+item.children[0].path : item.path+'/'+item.children[0].path"
:key="item.children[0].name">
<el-menu-item :index="parent ? parent + '/' + item.path+'/'+item.children[0].path : item.path+'/'+item.children[0].path">
<svg-icon v-if="item.children[0].meta&&item.children[0].meta.icon" :icon-class="item.children[0].meta.icon"></svg-icon>
<span v-if="item.children[0].meta&&item.children[0].meta.title" slot="title">{{generateTitle(item.children[0].meta.title)}}</span>
</el-menu-item>
</router-link>
<el-submenu v-else :index="item.name||item.path" :key="item.name">
<template slot="title">
<svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon>
<span v-if="item.meta&&item.meta.title" slot="title">{{generateTitle(item.meta.title)}}</span>
</template>
<template v-for="child in item.children" v-if="!child.hidden">
// 调用组件自身,用于循环
<sidebar-item :is-nest="true" class="nest-menu" v-if="child.children&&child.children.length>0" :routes="[child]" :parent="parent ? parent + '/' + item.path : item.path" :key="child.path"></sidebar-item>
<router-link v-else :to="parent ? parent + '/' + item.path+'/'+child.path : item.path+'/'+child.path" :key="child.name">
<el-menu-item :index="parent ? parent + '/' + item.path+'/'+child.path : item.path+'/'+child.path">
<svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon>
<span v-if="child.meta&&child.meta.title" slot="title">{{generateTitle(child.meta.title)}}</span>
</el-menu-item>
</router-link>
</template>
</el-submenu>
</template>
</div>
</template>
<script>
export default {
name: 'SidebarItem',
props: {
// routes参数是来自父组件navbar.vue文件,是整个路由表
routes: {
type: Array
},
// parent参数是sidebar-item.vue组件自身调用是传入的子路由
parent: {
type: String
}
},
methods: {
hasOneShowingChildren(children) {
const showingChildren = children.filter(item => {
return !item.hidden
})
if (showingChildren.length === 1) {
return true
}
return false
}
}
}
</script>
方法二:sidebar-item.vue文件(Menu开启router属性,Menu-item本身index作为跳转):
<template>
<div class="menu-wrapper">
<template v-for="item in routes" v-if="!item.hidden&&item.children">
<!--当路由只有一个子路由时-->
<el-menu-item v-if="hasOneShowingChildren(item.children) && !item.children[0].children&&!item.alwaysShow" :index="parent ? parent + '/' + item.path+'/'+item.children[0].path : item.path+'/'+item.children[0].path">
<svg-icon v-if="item.children[0].meta&&item.children[0].meta.icon" :icon-class="item.children[0].meta.icon"></svg-icon>
<span v-if="item.children[0].meta&&item.children[0].meta.title" slot="title">{{generateTitle(item.children[0].meta.title)}}</span>
</el-menu-item>
<el-submenu v-else :index="item.name||item.path" :key="item.name">
<template slot="title">
<svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon>
<span v-if="item.meta&&item.meta.title" slot="title">{{generateTitle(item.meta.title)}}</span>
</template>
<template v-for="child in item.children" v-if="!child.hidden">
<sidebar-item :is-nest="true" class="nest-menu" v-if="child.children&&child.children.length>0" :routes="[child]" :parent="parent ? parent + '/' + item.path : item.path" :key="child.path"></sidebar-item>
<el-menu-item v-else :index="parent ? parent + '/' + item.path+'/'+child.path : item.path+'/'+child.path">
<svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon>
<span v-if="child.meta&&child.meta.title" slot="title">{{generateTitle(child.meta.title)}}</span>
</el-menu-item>
</template>
</el-submenu>
</template>
</div>
</template>
<script>
export default {
name: 'SidebarItem',
props: {
// routes参数是来自父组件navbar.vue文件,是整个路由表
routes: {
type: Array
},
// parent参数是sidebar-item.vue组件自身调用是传入的子路由
parent: {
type: String
}
},
methods: {
hasOneShowingChildren(children) {
const showingChildren = children.filter(item => {
return !item.hidden
})
if (showingChildren.length === 1) {
return true
}
return false
}
}
}
</script>
以上就是动态生成多级导航栏,其中设置了hidden:true属性的路由不会显示在路由表中,因为在循环生成路由表时经过过滤,注意:当你不想多写代码的是时候应该开启Menu组件的routes属性,让Menu组件的Menu-Item的index属性来代替route-link来进行导航,无论何时Menu-Item的index属性也是控制当前显示那个Menu-Item,且是唯一的。多级导航栏的生成核心就是sidebar-item.vue文件的自身调用,就是组件内部调用组件自己。
先上错误代码(原始navbar.vue文件,文章开头是修改后的navbar.vue文件):
<template>
<el-menu
mode="vertical"
:show-timeout="200"
// $route.path是当前的路由
:default-active="$route.path"
:collapse="isCollapse"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
:unique-opened="true"
>
<template>
<script>
import SidebarItem from './SidebarItem'
export default {
components: { SidebarItem },
}
</script>
当我们点击页面的route-link进行跳转页面的时候,会发现导航栏的高亮显示效果消失了(样式缺失),效果如下:
下图是点击左侧导航栏coldd显示的页面,发现页面中第一个导航显示有颜色,且导航栏的coldd也是有颜色,表示我当前所在的页面是coldd页面,没毛病!!
但是当我点击页面中的第二个导航(跳转dasiaed页面)时,发现左侧导航栏coldd的颜色消失了,效果如下图
结果导致我们不知道自己在那个页面。虽然不影响功能,但是怎么就是觉得不对,是个问题,必须解决,所以我们应该去研究是什么原因导致。
对比文章中正确和错误navbar.vue文件,会发现不同的地方就在于,正确文件的default-active属性经过vue计算属性,而错误文件的default-active是直接引用路由,为什么会因为多了计算属性就可以解决问题呢?现在来解释以下。
首先,default-active属性控制的是导航栏的高亮显示,并且绑定的是Menu组件下的menu-item的index属性。
然后,在生成导航栏时menu-item的index属性是动态绑定路由的路径。
所以,default-active就是绑定路由的路径了(:default-active="$route.path"),route.path就是当前路由的路径,就像点击点击导航栏coldd时,路由高亮显示的是 /test/thirt/coldd,正常情况是没有毛病的,然而,当你点击页面中的路由(跳转dasiaed页面 /test/thirt/dasiaed)后,route.path就变了,变成了 /test/thirt/dasiaed,这时高亮显示的路由就是(/test/thirt/dasiaed),但是这个页面设置了hideen,没有在导航栏显示,就会造成导航栏的高亮显示效果消失。而我们希望不管点击页面中的那个路由,导航栏都始终是高亮显示,就是说default-active始终绑定路由/test/thirt/coldd。
原理弄清楚了,现在就好解决:
computed: {
routePath() {
if (this.$route.path === '/test/thirt/coldd' || this.$route.path === '/test/thirt/dasiaed') {
return '/test/thirt/coldd'
} else {
return this.$route.path
}
}
}
从计算属性可以看出,始终将default-active绑定路由/test/thirt/coldd,也就是匹配/test/thirt/路径下的所有路由都绑定’/test/thirt/coldd’,可以就可以避免页面路由引起导航路由高亮效果消失,如果/test/thirt/路径下很多路由可以使用正则匹配,少的话直接写完整路径。
抄袭不可怕,可怕的是你只复制一句话,虽然是核心,小白真不懂,我需要完整思路,完整的,完整的,最后还得自己去研究。。。