持续创作,加速成长!这是我参与「掘金日新计划 · 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。