项目场景:
项目场景:通过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的子路由