记录一下工作中使用element plus时候遇到的一个小bug
就是这个小箭头太折磨人了,因为我需要根据路由动态加载menu,所以对这个menu组件进行了一些处理,然后可能是因为破坏了它原来的层级关系吧导致折叠菜单的时候这个小箭头还在(官网的这个是会隐藏掉的)
后来我看了一下它的css,大概就是折叠的时候会在menu上加一个类类名为.el-menu--collapse然后可以根据这个类名进行item的名字隐藏
<style scoped lang="scss">
.menu-title {
font-size: 14px;
}
.el-menu--collapse .el-sub-menu__title span {
display: none;
}
.el-menu--collapse .el-menu-item span {
display: none;
}
</style>
这样也就隐藏了文本但是这个小箭头很顽固不能隐藏,于是我尝试在用一个不带scoped的style就把这个箭头隐藏了
<style scoped lang="scss">
.menu-title {
font-size: 14px;
}
.el-menu--collapse .el-sub-menu__title span {
display: none;
}
.el-menu--collapse .el-menu-item span {
display: none;
}
</style>
<style>
.el-menu--collapse .el-sub-menu .el-sub-menu__title .el-sub-menu__icon-arrow {
display: none;
}
</style>
到这里bug就解决了,这个细节虽然小但是很不雅观
根据路由动态渲染menu
讲到了动态渲染menu顺带记录一下吧
思想很简单就是根据路由去递归嘛然后由于菜单分为目录菜单el-sub-menu和功能菜单el-menu-item,这里目录菜单呢就是点击展开然后它的里面又可能包含了多个功能菜单
这里就有思路了,根据路由来看没有children的就是功能菜单,有children且长度不为0的就是目录菜单然后目录菜单下可能也有目录菜单显然就需要递归一下。
//MenuComponent.vue 这个就是整个menu
<template>
<el-menu
:default-active="activeIndex"
class="el-menu-vertical-demo"
:collapse="isCollapse"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
router
>
<div class="scroll-container">
<template v-for="item in filteredRoutes" :key="item.path">
<MenuItem :item="item" :isCollapse="props.isCollapse" />
</template>
</div>
</el-menu>
</template>
<script setup lang="ts">
import { ref, defineProps, defineComponent, computed } from 'vue'
import MenuItem from './MenuItem.vue'
const props = defineProps({
routes: Array,
activeIndex: String,
isCollapse: Boolean
})
const filteredRoutes = computed(() => {
if (props.routes?.length) {
return props.routes.filter((route: any) => {
if (route.meta && route.meta.show === false) {
return false
}
if (route.children) {
route.children = route.children.filter((child: any) => {
return !(child.meta && child.meta.show === false)
})
}
return true
})
} else {
return []
}
})
console.log(filteredRoutes.value)
</script>
<style scoped>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
.menu-title {
font-size: 14px;
}
.scroll-container {
max-height: calc(100vh - 60px); /* 调整这里的值以适应你的布局 */
overflow-y: auto;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
}
/* WebKit browsers (Safari, Chrome) */
.scroll-container::-webkit-scrollbar {
display: none; /* 隐藏滚动条 */
}
</style>
//MenuItem.vue 这个就是相应的菜单项,由于有el-sub-menu和el-menu-item两种我们这里进行了一个判断并且在组件中进行了一个递归,这样不管是几级的目录我们都可以动态渲染,具有一定可扩展性
<template>
<el-sub-menu
v-if="item.children && item.children.length > 0"
:index="item.path"
:popper-append-to-body="false"
>
<template #title>
<el-icon v-if="item.meta?.icon">
<component :is="item.meta.icon" />
</el-icon>
<span class="menu-title">{{ item.meta?.title }}</span>
</template>
<template v-for="child in item.children" :key="child.path">
<MenuItem :item="child" :is-collapse="isCollapse" />
</template>
</el-sub-menu>
<el-menu-item v-else :index="item.path">
<el-icon v-if="item.meta?.icon">
<component :is="item.meta.icon" />
</el-icon>
<template #title>
<span class="menu-title">{{ item.meta?.title }}</span>
</template>
</el-menu-item>
</template>
<script setup lang="ts">
import { defineProps, watch } from 'vue'
const props = defineProps({
item: {
type: Object,
required: true
},
isCollapse: {
type: Boolean,
default: false
}
})
</script>
<style scoped lang="scss">
.menu-title {
font-size: 14px;
}
.el-menu--collapse .el-sub-menu__title span {
display: none;
}
.el-menu--collapse .el-menu-item span {
display: none;
}
</style>
<style>
.el-menu--collapse .el-sub-menu .el-sub-menu__title .el-sub-menu__icon-arrow {
display: none;
}
</style>
然后就是使用这个组件了一般是在总布局的侧边栏
<MenuComponent
:routes="routes" // routes 是路由列表可以直接导入自己写的路由列表
:activeIndex="activeIndex" //这个是记录当前选中的index
:isCollapse="isCollapse" //这里传递是否折叠
/>
//注意在使用这个组件的布局页面要监听一下activeIndex的变化
// 使用 watch 监听路由变化
watch(
() => route.path,
newPath => {
activeIndex.value = newPath
},
{ immediate: true } // 初始化时立即同步一次
)
//路由中每一项加入meta
meta: {
title: '短信记录',
icon: getIconComponent('Document'), //获取element plus中的图标getIconComponent这个是我自定义的方法
show: true //是否显示在菜单中
}
//getIconComponent导入icon的方法如下
import * as Icons from '@element-plus/icons-vue'
import type { Component } from 'vue'
const iconMap: Record<string, Component> = Icons
export function getIconComponent(iconName: string): Component | undefined {
return iconMap[iconName]
}