vue3后台管理系统权限路由的实现
作者:mmseoamin日期:2024-04-27

最近做管理系统的时候,需要实现不同用户登陆所展示的菜单不同,查了不少帖子,总结下实现的步骤:

1.在router/index.js的代码

import { createRouter, createWebHistory,createWebHashHistory } from 'vue-router'
import NotFound from '@/pages/404/404.vue'
const routes = [
  { path: "/", component: () => import('@/pages/manage/manage.vue') },  // 登录页
  { path: "/login", component: () => import('@/pages/login/login.vue') },  // 登录页
  {path: "/manage", name: 'Manage', component: () => import('@/pages/manage/manage.vue')}, 
  { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
]
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes:routes
})
export default router

2.在main.js同目录建立permission.js

// 说明:路由守卫文件
import axios from "axios";
// 引入
import router from "./router";
// 判断用户无token 返回登录页提示有用
import { ElMessage } from 'element-plus';
let hasGetUserInfo = false;
// 一、前置守卫
router.beforeEach(async (to, from, next) => {
    const token = localStorage.getItem('token')
    if(!token && to.path !== '/login') return next('/login')
    if(token && to.path =='/login') {
        return next(from.path)
    }
    if(token && !hasGetUserInfo) {
    const res = await axios.get('https://mock.mengxuegu.com/mock/639d71742e0f396e51a5c945/example/menus')
    console.log(res)
    const ret = res.data.data.list;
        createRouters(ret);
        hasGetUserInfo =true
        return next(to.path);
    }
    next()
})
// 动态路由获取:注:之后完善项目直接考虑在登录的时候直接获取
// 直接缓存在 pinia 里
// 这里直接取数据,不请求
// const data = localStorage.getItem('routes')
// const allData = JSON.parse(data)
// function addRoutes() {
//     // 1、后端数据
//     createRouters(allData)
// }
// 拼接路由
function createRouters(result) {
    result.forEach((item) => {
        // 1、类型为0的菜单,子路由不为空,将子路由添加到manage里
        if (item.menuType === '0' && item.children.length > 0) {
            
            item.children.forEach((children) => {
                createRouterTemplate('Manage', children);
            })
        }
        // 2、menuType == 1, 子路由为空
        if (item.menuType === '1' && item.children.length === 0) {
            createRouterTemplate('Manage', item);
        }
        // 3、递归层级
        if (item.children.length > 0) {
            createRouters(item.children);
        }
    });
}
// 把router 的动态路由进行封装
function createRouterTemplate(fatherRouter, item) {
    router.addRoute(fatherRouter, {
        path: item.path,
        name: item.name,
        meta: {
            title: item.meta.title, // 面包屑用
            requiresAuth: item.meta.requiresAuth,
            roles: item.meta.roles,
            breadcrumb: item.meta.breadcrumb,
            keepAlive: item.meta.keepAlive
        },
        // /* @vite-ignore */ :处理vite动态导入的警告
        component: () => import(/* @vite-ignore */ `./views${item.component}`)
    })
    }
// 二、后置守卫
router.afterEach((to) => {
    // 标签抬头
  
})
// main.js 导入的为这个router
export default router

3.然后在mian.js引入:

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './permission'; // 现router
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(ElementPlus)
app.mount('#app')

4.后端返回数据格式:

[
    {
        "id": "1",
        "name": "Home",
        "path": "/home",
        "component": "/home/index.vue",
        "menuType": "1",
        "icon": "Discount",
        "sort": 0,
        "meta": {
            "title": "系统首页",
            "requiresAuth": null,
            "roles": [],
            "breadcrumb": [
                {}
            ],
            "keepAlive": null
        },
        "children": []
    },
    {
        "id": "2",
        "name": "System",
        "path": "/system",
        "component": "/system/index.vue",
        "menuType": "0",
        "icon": "Operation",
        "sort": 0,
        "meta": {
            "title": "系统管理",
            "requiresAuth": null,
            "roles": [],
            "breadcrumb": [
                {}
            ],
            "keepAlive": null
        },
        "children": [
            {
                "id": "211",
                "name": "User",
                "path": "/user",
                "component": "/user/index.vue",
                "menuType": "1",
                "icon": "user",
                "sort": 0,
                "meta": {
                    "title": "用户管理",
                    "requiresAuth": null,
                    "roles": [],
                    "breadcrumb": [
                        {}
                    ],
                    "keepAlive": null
                },
                "children": []
            },
            {
                "id": "222",
                "name": "Menu",
                "path": "/menu",
                "component": "/menu/index.vue",
                "menuType": "1",
                "icon": "Menu",
                "sort": 0,
                "meta": {
                    "title": "菜单管理",
                    "requiresAuth": null,
                    "roles": [],
                    "breadcrumb": [
                        {}
                    ],
                    "keepAlive": null
                },
                "children": []
            },
            {
                "id": "223",
                "name": "Role",
                "path": "/role",
                "component": "/role/index.vue",
                "menuType": "1",
                "icon": "Avatar",
                "sort": 0,
                "meta": {
                    "title": "角色管理",
                    "requiresAuth": null,
                    "roles": [],
                    "breadcrumb": [
                        {}
                    ],
                    "keepAlive": null
                },
                "children": []
            }
        ]
    },
    {
        "id": "3",
        "name": "Log",
        "path": "/log",
        "component": "/log/index.vue",
        "menuType": "1",
        "icon": "Notebook",
        "sort": 0,
        "meta": {
            "title": "日志管理",
            "requiresAuth": null,
            "roles": [],
            "breadcrumb": [
                {}
            ],
            "keepAlive": null
        },
        "children": []
    },
    {
        "id": "4",
        "name": "Study",
        "path": "/study",
        "component": "/study/index.vue",
        "menuType": "0",
        "icon": "Notebook",
        "sort": 0,
        "meta": {
            "title": "学习管理",
            "requiresAuth": null,
            "roles": [],
            "breadcrumb": [
                {}
            ],
            "keepAlive": null
        },
        "children": [
            {
                "id": "441",
                "name": "StudyUser",
                "path": "/studyUser",
                "component": "/study/user/index.vue",
                "menuType": "0",
                "icon": "Notebook",
                "sort": 0,
                "meta": {
                    "title": "用户管理",
                    "requiresAuth": null,
                    "roles": [],
                    "breadcrumb": [
                        {}
                    ],
                    "keepAlive": null
                },
                "children": [
                    {
                        "id": "4441",
                        "name": "Student",
                        "path": "/student",
                        "component": "/study/user/student/index.vue",
                        "menuType": "1",
                        "icon": "Notebook",
                        "sort": 0,
                        "meta": {
                            "title": "学生管理",
                            "requiresAuth": null,
                            "roles": [],
                            "breadcrumb": [
                                {}
                            ],
                            "keepAlive": null
                        },
                        "children": []
                    },
                    {
                        "id": "4442",
                        "name": "Teacher",
                        "path": "/teacher",
                        "component": "/study/user/teacher/index.vue",
                        "menuType": "1",
                        "icon": "Notebook",
                        "sort": 0,
                        "meta": {
                            "title": "教师管理",
                            "requiresAuth": null,
                            "roles": [],
                            "breadcrumb": [
                                {}
                            ],
                            "keepAlive": null
                        },
                        "children": []
                    }
                ]
            }
           
        ]
    }
]

5.首页的代码:

6.组件AsideMenu.vue的代码:


   
   

7.组件LeftSubMenu.vue的代码


   

这样就实现该功能,登陆页面就是登陆保存token的操作。

感谢VueRouter4 - 动态路由刷新变空白或404_vue刷新页面后路由匹配到空白-CSDN博客,Vue3+Vue-Router+Element-Plus根据后端数据实现前端动态路由——权限管理模块_vue3动态路由权限-CSDN博客