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

介绍:目前使用的路由表是三级路由表,文章中使用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页面,没毛病!!
vue项目 使用Element-UI的NavMenu 遍历路由表生成导航菜单与点击页面路由时导航菜单失去高亮显示效果_第1张图片
但是当我点击页面中的第二个导航(跳转dasiaed页面)时,发现左侧导航栏coldd的颜色消失了,效果如下图
vue项目 使用Element-UI的NavMenu 遍历路由表生成导航菜单与点击页面路由时导航菜单失去高亮显示效果_第2张图片
结果导致我们不知道自己在那个页面。虽然不影响功能,但是怎么就是觉得不对,是个问题,必须解决,所以我们应该去研究是什么原因导致。
对比文章中正确和错误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/路径下很多路由可以使用正则匹配,少的话直接写完整路径。
抄袭不可怕,可怕的是你只复制一句话,虽然是核心,小白真不懂,我需要完整思路,完整的,完整的,最后还得自己去研究。。。

你可能感兴趣的:(web前端)