项目场景:
项目场景:通过vue3+elementPlus的menu组件结合router路由属性实现动态侧边栏效果,实现侧边栏动态跟随着路由的变化。搜了很多文档,描述的都不够完整。
效果如下:
点击侧边栏路由同步跳转展示对应的页面
问题描述
- menuRoutes就是路由中routes对应的数组进行了一次过滤。
- v-if是对有子路由的进行展示子级,否则展示没有子级的menu
- component的is直接放了icon不展示,创建图标映射表包裹着就能展示了
具体代码如下:要在menu组件上加上router属性
menu组件:
<el-menu text-color="#fff" background-color="#001529" router :default-openeds="['0', '1']" > <!-- 遍历 menuRoutes,动态渲染菜单项 --> <template v-for="(item, index) in menuRoutes"> <!-- 如果有子路由,使用 el-sub-menu --> <el-sub-menu v-if="item.children && item.children.length" :key="index" :index="index + ''" > <template #title> <el-icon> <component :is="iconComponents[item.meta.icon]"></component> </el-icon> <span>{{ item.meta.title }}</span> </template> <!-- 二级菜单 --> <el-menu-item v-for="(item2, index2) in item.children" :key="index2" :index="item2.path" :class="$route.path === item2.path ? 'is-active' : ''" > <template #title> <el-icon> <component :is="iconComponents[item2.meta.icon]" ></component> </el-icon> {{ item2.meta.title }} </template> </el-menu-item> </el-sub-menu> <!-- 如果没有子路由,使用 el-menu-item --> <el-menu-item v-else :index="item.path" :class="$route.path === item.path ? 'is-active' : ''" > <el-icon> <component :is="iconComponents[item.meta.icon]"></component> </el-icon> <span>{{ item.meta.title }}</span> </el-menu-item> </template> </el-menu>
复制
这里icon要进行引入,引入之后再放到图标映射表里面,再把icon组件进行包裹
import { HomeFilled, Lock, Location, Histogram, UserFilled, User, Menu, } from "@element-plus/icons-vue"; // 创建图标映射表 const iconComponents = { Location, HomeFilled, Lock, UserFilled, User, Histogram, Menu, // 添加其他图标组件映射 }; // 过滤掉不需要展示的路由,并调整 layout 的子路由 const menuRoutes = computed(() => { // 获取所有路由 const routes = $router.options.routes; // 过滤掉不需要展示的路由并展开 layout 子路由 const adjustedRoutes = routes.flatMap((route) => { // 隐藏 'layout' 路由但展示其子路由作为一级路由 if (route.path === "/" && route.children) { return route.children.map((child) => ({ ...child, path: child.path, meta: child.meta, })); } // 如果路由设置为隐藏,则跳过 if (route.meta?.hidden) { return []; } return route; }); return adjustedRoutes; });
复制
为了方便调试理解,我把整个routes路由代码放上来,
- 在meta里面的hidden来控制展示和隐藏,true为隐藏,false为展示
- title就是menu上展示的字段
- icon这里手动写上,必须在映射表方法写上和import引入
比如这里的layout是不需要展示的,但layout的子路由home又需要展示,就得menuRoutes进行计算属性那里过滤。
export const constantRoute = [ { path: "/login", component: () => import("@/views/login/index.vue"), // component: login, name: "login", meta: { title: '登录', icon: "Edit", hidden: true } }, { path: "/", component: () => import("@/layout/index.vue"), name: "layout", meta: { title: 'layout', hidden: true, icon: 'Suitcase', }, redirect: "/home", children: [ { path: "/home", component: () => import("@/views/home/index.vue"), meta: { title: "首页", hidden: false, icon: "HomeFilled", }, }, ], }, { path: "/404", component: () => import("@/views/404/index.vue"), name: "404", meta: { title: '404', hidden: true } }, // 权限管理 { path: "/acl", component: () => import("@/layout/index.vue"), name: "Acl", meta: { title: '权限管理', hidden: false, icon: 'Lock' }, children: [ { path: "/user", component: () => import("@/views/acl/user/index.vue"), meta: { title: '用户管理', hidden: false, icon: 'UserFilled' }, }, { path: "/role", component: () => import("@/views/acl/role/index.vue"), meta: { title: '角色管理', hidden: false, icon: 'User' }, }, { path: "/permission", component: () => import("@/views/acl/permission/index.vue"), meta: { title: '菜单管理', hidden: false, icon: 'Menu' }, } ] }, ];
复制
最后
最后在内容展示区要放routerview,展示layout的子路由