本文的动态路由是由前端实现的,因为本项目有多角色登录同一平台,但是又不想涉及后端,所以是简便式的动态路由与动态菜单
1. 步骤
- 准备路由数组
- 新增方法,动态修改路由数组部分参数
- 通过router动态拼接路由
- 通过路由数组动态生成菜单
2. 路由数组
export const routes = [
{
path: "/system",
name: "System",
component: () => import("@/layout/Index.vue"),
meta: {
title: "系统管理",
hide: true,
icon: "Setting",
},
children: [
{
path: "/user",
component: () => import("@/views/system/user/Index.vue"),
meta: {
title: "用户管理",
hide: true,
icon: "User",
},
},
{
path: "/notice",
component: () => import("@/views/system/notice/Index.vue"),
meta: {
title: "公告管理",
hide: true,
icon: "ChatLineSquare",
},
},
]
},
{
path: "/message",
name: "Message",
component: () => import("@/layout/Index.vue"),
meta: {
title: "信息管理",
hide: true,
icon: "ChatDotSquare",
},
children: [
{
path: "/goods_type",
component: () => import("@/views/information_manager/goods_type/Index.vue"),
meta: {
title: "商品分类管理",
hide: true,
icon: "Goods",
},
},
{
path: "/business",
component: () => import("@/views/information_manager/business/Index.vue"),
meta: {
title: "商家信息管理",
hide: true,
icon: "UserFilled",
},
},
]
},
]
// 根据某些条件动态修改路由数组部分数据
export const updateRoute = () => {
const user = JSON.parse(localStorage.getItem("user")) // 获取用户数据
const flag = user && user.role === "ADMIN" // 判断条件:登录账号并且账号是管理员
routes.forEach(item => { // 用户登录了并且登录的是管理员账号,才会显示所有菜单,反之隐藏部分菜单
item.meta.hide = flag;
if (item.children.length > 0) { // 如果一级路由还有子路由,继续循环更新路由数组
item.children.forEach(children => {
children.meta.hide = flag
})
}
})
}
3. 动态拼接
import {createRouter, createWebHistory} from 'vue-router';
import {routes} from "@/router/routes.ts";
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: "/",
name: "Layout",
component: () => import("@/layout/Index.vue"),
redirect: '/home',
meta: {
title: "",
hide: false,
},
children: [
{
path: "/home",
component: () => import("@/views/system/home/Index.vue"),
name: "home",
meta: {
title: "主页",
hide: true,
icon: "House",
},
},
]
},
{
path: '/login',
component: () => import('@/views/login/Index.vue'),
name: 'Login',
meta: {
title: "登录",
hide: false,
},
},
{
path: '/404',
component: () => import('@/views/404/Index.vue'),
name: '404',
meta: {
title: "404",
hide: false,
},
},
{
path: "/:pathMatch(.*)*",
redirect: "/404",
name: "Any",
meta: {
title: "任意路由",
hide: false,
},
}
]
})
// 动态拼接路由数组
const setRoute = () => {
routes.forEach(item => {
router.addRoute(item) // 添加一级路由
if (item.children.length > 0) { // 如果拥有二级路由
item.children.forEach(children => {
router.addRoute(item.name, children) // 将二级数组拼到一级路由中,如 {item, children:[children]}
})
}
})
}
setRoute()
export default router;
4. 动态生成菜单
<script lang="ts" setup>
import { useRouter } from "vue-router";
import {updateRoute} from "@/router/routes.ts";
const router = useRouter();
// 页面变量
const menuList = router.getRoutes()
updateRoute()
// 事件定义
const pushPath = (path: string) => { // 点击导航栏按钮对应跳转到页面
router.push(path)
}
</script>
<template>
<div v-for="menu in menuList" :key="menu.path">
<!-- 没有子路由 -->
<div v-if="menu.meta.hide">
<el-menu-item v-if="!menu.children" :index="menu.path" @click="pushPath(menu.path)">
<el-icon>
<component :is="menu.meta.icon"/>
</el-icon>
<template #title>
<span>
{{ menu.meta.title }}
</span>
</template>
</el-menu-item>
</div>
<!-- 只有一个子路由,不显示父路由 -->
<div v-if="menu.children && !menu.meta.hide">
<el-menu-item v-if="menu.children.length == 1" :index="menu.children[0].path"
@click="pushPath(menu.children[0].path)">
<template #title>
<el-icon>
<component :is="menu.children[0].meta.icon"/>
</el-icon>
<span>
{{ menu.children[0].meta.title }}
</span>
</template>
</el-menu-item>
</div>
<!-- 只有一个子路由,显示父路由 -->
<div v-if="menu.children && menu.meta.hide">
<el-sub-menu
v-if="menu.children.length == 1"
:index="menu.children[0].path"
>
<template #title>
<el-icon>
<component :is="menu.meta.icon"/>
</el-icon>
<span> {{ menu.meta.title }} </span>
</template>
<el-menu-item-group>
<el-menu-item :index="menu.children[0].path" @click="pushPath(menu.children[0].path)">
<template #title>
<el-icon>
<component :is="menu.children[0].meta.icon"/>
</el-icon>
<span> {{ menu.children[0].meta.title }} </span>
</template>
</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
</div>
<!-- 多个子路由 -->
<div v-if="menu.meta.hide">
<el-sub-menu
:index="menu.path"
v-if="menu.children && menu?.children.length > 1"
>
<template #title>
<el-icon>
<component :is="menu.meta.icon"/>
</el-icon>
<span> {{ menu.meta.title }} </span>
</template>
<el-menu-item-group v-for="menuChildren in menu.children">
<el-menu-item v-if="menuChildren.meta.hide" :index="menuChildren.path" @click="pushPath(menuChildren.path)">
<template #title>
<el-icon>
<component :is="menuChildren.meta.icon"/>
</el-icon>
<span> {{ menuChildren.meta.title }} </span>
</template>
</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
</div>
</div>
</template>
<style scoped>
</style>