el-menu递归组件实现多级菜单(vue3+element plus版)
vue2 + element ui版:点击此处
1. 外层菜单组件:
LeftMenu.vue
<template> <el-menu :default-active="activeMenu" router :class="'menu-left'" :default-openeds="openedsArr" text-color="#fff" > <LeftSubMenu :menuData="menuData"></LeftSubMenu> </el-menu> </template> <script setup> import LeftSubMenu from "@/components/LeftSubMenu.vue"; import { computed } from "vue"; import { useRouter } from "vue-router"; const openedsArr = props.menuData.map((item) => { return item.path; }); const props = defineProps({ menuData: { type: Array, default: [], }, }); const activeMenu = computed(() => { const router = useRouter(); const { meta, path } = router.currentRoute.value; if (meta.matchPath2) { return meta.matchPath2; } else { return path; } }); </script> <style scoped> .menu-left { flex: 1; padding: 0 8px; border-right: none; background: none; } .menu-left:deep(.el-menu), .menu-left:deep(.el-sub-menu__title:hover) { background: none; } .menu-left:deep(.el-menu-item), .menu-left:deep(.el-sub-menu__title) { height: 36px; margin-bottom: 4px; border-radius: 4px; color: var(--text-main-color) !important; } .menu-left:deep(.el-menu-item:hover .icon), .menu-left:deep(.el-menu-item.is-active .icon) { filter: invert(100%); -webkit-filter: invert(100%); } .menu-left:deep(.el-menu-item:hover), .menu-left:deep(.el-menu-item.is-active) { color: #ffffff !important; background-color: #243158; } </style>
2. 子菜单组件(递归主体):
LeftSubMenu.vue
<template> <template v-for="item in menuData"> <el-sub-menu :key="item.path" v-if="item.children && item.children.length > 0" :index="item.path" :class="item.icon ? '' : 'noIcon'" > <template #title> <img class="icon pd-r-10" :src="curRoute.indexOf(item.path) != -1 ? item.iconActive : item.icon" /> <img class="icon pd-r-10" :src="item.icon" /> <span>{{ item.label }}</span> </template> <LeftSubMenu :menuData="item.children"></LeftSubMenu> </el-sub-menu> <el-menu-item :key="item.id" v-else :index="item.path" :disabled="item.disabled" > <template #title> <img class="icon pd-r-10" :src="item.icon" /> <span>{{ item.label }}</span> </template> </el-menu-item> </template> </template> <script setup> import LeftSubMenu from "./LeftSubMenu.vue"; import { computed } from "vue"; import { useRouter } from "vue-router"; const props = defineProps({ menuData: { type: Array, default: [], }, }); const curRoute = computed(() => { const router = useRouter(); const { path } = router.currentRoute.value; return path; }); </script>
3. 使用:
... <LeftMenu :menuData="menuList"></LeftMenu> ...
const menuList = [ { title: "菜单一", path: "/menutest/menu1", icon: new URL("@/assets/images/icons/icon.png", import.meta.url).href, iconActive: new URL("@/assets/images/icons/icon_active.png", import.meta.url).href, children: [ { title: "子菜单一", path: "/menutest/menu1/menu1-1", // disabled: true, }, { title: "子菜单二", path: "/menutest/menu1/menu1-2", }, ], }, { title: "菜单二", path: "/menutest/menu2", icon: new URL("@/assets/images/icons/icon.png", import.meta.url).href, iconActive: new URL("@/assets/images/icons/icon_active.png", import.meta.url).href, children: [ { title: "子菜单一", path: "/menutest/menu2/menu2-1", }, { title: "子菜单二", path: "/menutest/menu2/menu2-2", children: [ { title: "孙子菜单一", path: "/menutest/menu2/menu2-2/menu2-1-1", }, { title: "孙子菜单二", path: "/menutest/menu2/menu2-2/menu2-2-2", }, ], }, { title: "子菜单三", path: "/menutest/menu2/menu2-3", }, ], }, { title: "菜单三", path: "/menutest/menu3", icon: new URL("@/assets/images/icons/icon.png", import.meta.url).href, iconActive: new URL("@/assets/images/icons/icon_active.png", import.meta.url).href, }, ];
注意vite图片引入的方式
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!