vue项目 使用Element-UI的NavMenu 遍历路由表生成导航菜单与点击页面路由时导航菜单失去高亮显示效果

web前端 专栏收录该内容
5 篇文章 0 订阅

介绍:目前使用的路由表是三级路由表,文章中使用Element-UI动态生成导航栏可以有N级路由嵌套,但是事实上不会有那么多级路由,但是为了方便还是一次性写好,使用时就是复制文件就好

虚拟路由表:(hidden属性用于判断是否将路由显示在导航栏,true表示隐藏)
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 遍历路由表生成导航菜单(以下是正确代码)

备注: 在使用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/路径下很多路由可以使用正则匹配,少的话直接写完整路径。
抄袭不可怕,可怕的是你只复制一句话,虽然是核心,小白真不懂,我需要完整思路,完整的,完整的,最后还得自己去研究。。。

  • 0
    点赞
  • 8
    评论
  • 5
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值