前端简便式动态路由,实现多角色登录不同菜单

本文介绍了如何在前端实现动态路由,以适应多角色登录的场景,通过操作路由数组动态生成菜单,同时考虑了权限控制,仅管理员能显示全部菜单。
摘要由CSDN通过智能技术生成

本文的动态路由是由前端实现的,因为本项目有多角色登录同一平台,但是又不想涉及后端,所以是简便式的动态路由与动态菜单

1. 步骤

  1. 准备路由数组
  2. 新增方法,动态修改路由数组部分参数
  3. 通过router动态拼接路由
  4. 通过路由数组动态生成菜单

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>
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值