el-menu 菜单组件在微前端中的使用优化

509 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

废话少说先上代码

菜单组件代码(202203)

<el-menu @select="redirectRoute" :collapse="isCollapse" :default-active="currentMenu" background-color="transparent" :unique-opened="true">
  <xxx-navMenu :navMenus="menuData"></xxx-navMenu>
</el-menu>
<template>
  <div class="navMenu">
    <label v-for="navMenu in navMenus" :key="navMenu.menuId">
      <!-- 子菜单 -->
      <el-menu-item id="menuitem" v-if="navMenu&&navMenu.type===1&&navMenu.childs===null" :index="navMenu.sn + '/' + navMenu.url">
        <div>
          <i :class="navMenu.icon"></i>
          <span class="span-ellipsis" slot="title" :title="navMenu.name">{{ dealAliasName(navMenu) }}</span>
        </div>
      </el-menu-item>
      <!-- 父菜单 -->
      <el-submenu id="menuitems" v-if="navMenu&&navMenu.type===0&&navMenu.childs!==null&&navMenu.childs.length!==0" :index="navMenu.sn + '/' + navMenu.url">
        <template slot="title">
          <div class="menu-root">
            <i :class="navMenu.icon"></i>
            <span class="span-ellipsis" :title="navMenu.name">{{ dealAliasName(navMenu) }}</span>
          </div>
        </template>
        <xxx-navMenu :navMenus="navMenu.childs"></xxx-navMenu>
      </el-submenu>
      <!-- 没有子菜单的父菜单 -->
      <el-submenu id="menuitems" v-if="navMenu&&navMenu.type===0&&(navMenu.childs===null||navMenu.childs.length===0)" :index="navMenu.sn + '/' + navMenu.url">
        <template slot="title">
          <div class="menu-root">
            <i :class="navMenu.icon"></i>
            <span class="span-ellipsis" :title="navMenu.name">{{ dealAliasName(navMenu) }}</span>
          </div>
        </template>
      </el-submenu>
    </label>
  </div>
</template>
redirectRoute (index) {
  // index绑定需要唯一,然而url可能重复,且router模式直接根据index绑定。
  // 所以关闭router模式,采用index绑定sn|url,手动选中跳转截取url。
  if (index.indexOf('/')) {
    window.localStorage.setItem('MENU_SN', index.substring(0, index.indexOf('/')))
    this.$router.push({ path: index.substring(index.indexOf('/')) })
  }
}
watch: {
  $route: {
    handler (val) {
      this.currentMenu = window.localStorage.getItem('MENU_SN') + val.path
      // 处理子路由的菜单选中问题 写死子路由的父菜单节点
      if (this.currentMenu.indexOf('svg-') !== -1) {
        this.currentMenu = 'subSvgDiagram/svgDiagram'
      } else if (this.currentMenu.indexOf('tpl-') !== -1) {
        this.currentMenu = 'subTplDiagram/tplDiagram'
      }
    },
    immediate: true
  }
},

优化点和问题点

一、舍弃router模式

舍弃原因:

启用vue-router模式会在激活导航时以 index 作为 path 进行路由跳转。

而index绑定值需要唯一,如果存在路由为空串''容易出现点击空串的节点展开了全部等问题。

且当前系统采用微前端架构,系统菜单配置时,容易出现路由不唯一的情况,只有sn(或code或id)才能保证唯一性。

于是只能舍弃router模式,绑定select函数手动跳转路由。

二、index的绑定需唯一

不适用router模式后,此时index绑定又成了问题,@select方法传过来的参数就是index绑定的值。

且不能绑定url字段(因为存在重复的url),本人采取的解决办法是:

:index="navMenu.sn + '/' + navMenu.url"

index绑定唯一标识sn +'/'+ 不带开头斜杠的url

此时保证了唯一性,且可以截取'/'进行路由跳转。

三、注意index的唯一性报错

el-menu-item和el-submenu绑定index的时候报错:

Invalid prop: custom validator check failed for prop "index".

请注意官方说明了:

index 唯一标志 string/null — null

若绑定的是数值类型就会报错,需要转成字符串类型。

四、菜单二次点击才有选中样式

选中菜单,路由跳转了,但需要点击两次才有选中的颜色。

F12查看,第一次点击时没有绑定上.isactive,第二次点击才绑定该样式。

原来使用router模式是没有这个问题的,但是现在不用router模式,通过select方法跳转路由。

最后尝试将default-active进行修改,按照如下绑定:

:default-active="$route.name + $route.path"

咦~可以了。但是当访问子路由时,$route.name + $route.path的绑定就有问题了,无法选中了。

五、default-active取值$route导致子路由无法选中

因为默认激活选中的菜单绑定了当前路由的"名称/路径"::default-active="$route.name + $route.path"

但是存在某个页面跳转到某个子路由,导致菜单选中会消失。

于是进行如下改造:

:default-active="currentMenu"

需要通过监听路由变化,手动处理当前绑定的菜单:

watch: {
  $route: {
    handler (val) {
      this.currentMenu = window.localStorage.getItem('MENU_SN') + val.path
      // 处理子路由的菜单选中问题 写死子路由的父菜单节点
      if (this.currentMenu.indexOf('svg-') !== -1) {
        this.currentMenu = 'subSvgDiagram/svgDiagram'
      } else if (this.currentMenu.indexOf('tpl-') !== -1) {
        this.currentMenu = 'subTplDiagram/tplDiagram'
      }
    },
    immediate: true
  }
},

六、后退时的路由默认选中

后退到首页/home,菜单树里navMenu.sn没有首页home这个路由。

navMenu.sn!==default-active选中前一个高亮始终不变。此时应该清除选中。

但是经测试,当前使用element ui@2.15.1好像没有文中的问题了,貌似官方修复了这个bug。

文章详见:juejin.cn/post/708555…