vue+iView 动态侧边栏菜单保持高亮选中
iview 组件在使用过程中,多多少少有一些小坑,本文简单罗列一二:
避坑指南: 关于iview 侧边栏菜单未能展开高亮选中回显问题
应用场景:iview-admin下接入动态菜单后,刷新或链接跳入时回显失效
简单就是两个方面:动态菜单接入前和动态菜单接入后菜单保持高亮选中问题。
一,动态菜单接入前:
本博客中有一篇文章简单介绍了 iView跳转子菜单父级菜单保持高亮的实现方法:
:active-name="$route.name"
<side-menu
accordion
ref="sideMenu"
:active-name="$route.name"
:collapsed="collapsed"
@on-select="turnToPage"
:menu-list="menuList">
</side-menu>
菜单保持高亮选中
1,方法一:
跳转前页面的name保持一致,跳转页中meta中加
recoverName: ‘user-info’ // 和跳转前页面的name保持一致。
2,方法二:
:active-name="activeName()"
<side-menu
accordion
ref="sideMenu"
:active-name="activeName()"
:collapsed="collapsed"
@on-select="turnToPage"
:menu-list="menuList"
>
method中加
activeName() {
if (this.$route.meta.activeName){
return this.$route.meta.activeName;
}else{
return this.$route.name;
}
},
这样两种方法都是没有问题的,但接入权限使用动态菜单时就存在一个问题:
刷新页面或使用链接跳转进入时就会出现跳转到首页,父菜单收起,子菜单未保持选中高亮
二,动态菜单接入后:
本博客中另一篇文章也简单介绍了 iview 动态渲染显示侧边栏菜单及获取选中数据,渲染方法:
:menu-list="menuList"
主要是动态菜单接入后,菜单高亮选中就会失效
main.vue 的mounted中接口动态获取菜单数据,渲染侧边栏菜单。
store.dispatch('getMenuData').then(res => {
}
菜单高亮选中失效问题解决方法:
我们可以通过方法 iview menu updateOpened updateActiveName属性:
updateOpened()
updateActiveName()
this.$refs.sideMenu.updateOpenName(this.$route.name);
在菜单请求后调用,但是必须在$nextTick里使用才有效
store.dispatch('getMenuData').then(res => {
if(this.$store.getters.menuList){
this.$nextTick(() => {
this.$refs.sideMenu.updateOpenName(this.$route.name);
});
}
})
这样无论跳转还是强制刷新,侧边栏菜单是会展开的,但是选中的子菜单
依旧没有高亮选中回显
可以在side-menu侧边栏菜单组件中加updateActiveName属性方法更新
this.$refs.menu.updateActiveName() //保持高亮选中
updateOpenName (name) {
if (name === this.$config.homeName) this.openedNames = []
else this.openedNames = this.getOpenedNamesByActiveName(name)
if(this.activeName){
this.$nextTick(() => {
this.$refs.menu.updateActiveName() //保持高亮选中
})
}
},
三,部分主要代码:
1.main.vue中:
import SideMenu from "./components/side-menu";
<Sider
hide-trigger
collapsible
:width="200"
:collapsed-width="64"
v-model="collapsed"
class="left-sider"
:style="{overflow: 'hidden'}"
>
<side-menu
accordion
ref="sideMenu"
:active-name="activeName()"
:collapsed="collapsed"
@on-select="turnToPage"
:menu-list="menuList"
>
</side-menu>
</Sider>
2.side-menu组件中
<template>
<div class="side-menu-wrapper">
<slot></slot>
<Menu ref="menu" v-show="!collapsed" :active-name="activeName" :open-names="openedNames" :accordion="accordion" :theme="theme" width="auto" @on-select="handleSelect">
<template v-for="item in menuList">
<template v-if="item.children && item.children.length === 1">
<side-menu-item v-if="showChildren(item)" :key="`menu-${item.name}`" :parent-item="item"></side-menu-item>
<menu-item v-else :name="getNameOrHref(item, true)" :key="`menu-${item.children[0].name}`"><common-icon :type="item.children[0].icon || ''"/><span>{{ showTitle(item.children[0]) }}</span></menu-item>
</template>
<template v-else>
<side-menu-item v-if="showChildren(item)" :key="`menu-${item.name}`" :parent-item="item"></side-menu-item>
<menu-item v-else :name="getNameOrHref(item)" :key="`menu-${item.name}`"><common-icon :type="item.icon || ''"/><span>{{ showTitle(item) }}</span></menu-item>
</template>
</template>
</Menu>
<div class="menu-collapsed" v-show="collapsed" :list="menuList">
<template v-for="item in menuList">
<collapsed-menu :center="true" v-if="item.children && item.children.length > 1" @on-click="handleSelect" hide-title :root-icon-size="rootIconSize" :icon-size="iconSize" :theme="theme" :parent-item="item" :key="`drop-menu-${item.name}`"></collapsed-menu>
<Tooltip transfer v-else :content="showTitle(item.children && item.children[0] ? item.children[0] : item)" placement="right" :key="`drop-menu-${item.name}`">
<a @click="handleSelect(getNameOrHref(item, true))" class="drop-menu-a" :style="{textAlign: 'center'}"><common-icon :right="0" :size="item.size" :color="textColor" :type="item.icon || (item.children && item.children[0].icon)"/></a>
</Tooltip>
</template>
</div>
</div>
</template>
<script>
import SideMenuItem from './side-menu-item.vue'
import CollapsedMenu from './collapsed-menu.vue'
import { getUnion } from '@/libs/tools'
import mixin from './mixin'
export default {
name: 'SideMenu',
mixins: [ mixin ],
components: {
SideMenuItem,
CollapsedMenu
},
props: {
menuList: {
type: Array,
default () {
return []
}
},
collapsed: {
type: Boolean
},
theme: {
type: String,
default: 'dark'
},
rootIconSize: {
type: Number,
default: 20
},
iconSize: {
type: Number,
default: 16
},
accordion: Boolean,
activeName: {
type: String,
default: ''
},
openNames: {
type: Array,
default: () => []
}
},
data () {
return {
openedNames: [],
}
},
methods: {
handleSelect (name) {
this.$emit('on-select', name)
},
getOpenedNamesByActiveName (name) {
return this.$route.matched.map(item => item.name).filter(item => item !== name)
},
updateOpenName (name) {
if (name === this.$config.homeName) this.openedNames = []
else this.openedNames = this.getOpenedNamesByActiveName(name)
if(this.activeName){
this.$nextTick(() => {
this.$refs.menu.updateActiveName()
})
}
},
},
computed: {
textColor () {
return this.theme === 'dark' ? '#fff' : '#495060'
}
},
watch: {
activeName (name) {
if (this.accordion) this.openedNames = this.getOpenedNamesByActiveName(name)
else this.openedNames = getUnion(this.openedNames, this.getOpenedNamesByActiveName(name))
},
openNames (newNames) {
this.openedNames = newNames
},
openedNames () {
this.$nextTick(() => {
this.$refs.menu.updateOpened()
})
}
},
mounted () {
this.openedNames = getUnion(this.openedNames, this.getOpenedNamesByActiveName(name))
}
}
</script>
<style lang="less">
@import './side-menu.less';
</style>
往期更多精彩:
1.vue+iView 权限实践之动态显示侧边栏菜单
2.vue+iView 跳转子菜单父级菜单保持高亮
3.vue+iView 树形菜单回显与选中
4.vue+iView 实现导入与导出excel功能
5.vue+iView table分页勾选记忆功能
喜欢就多多点赞关注。