vue3后台管理系统权限路由的实现

03-29 1705阅读 0评论

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

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.首页的代码:

import { RouterView ,useRouter} from 'vue-router';
import AsideMenu from '@/components/AsideMenu.vue'
const router = useRouter()
const logout = ()=>{
  localStorage.removeItem('token')
  router.replace('/login')
}


    
      
        
            
        
        
          
            推出登陆
          
            
        
      
    
  

6.组件AsideMenu.vue的代码:

    
        
    

   

import LeftSubMenu from "./LeftSubMenu.vue";
import { computed } from "vue";
import { useRouter } from "vue-router";
import { onMounted,ref } from "vue";
const treeMenu = ref([])
const openedsArr = treeMenu.value.map((item) => {
    return item.path;
});
onMounted(()=>{
    const data = localStorage.getItem('menuData')
    treeMenu.value = JSON.parse(data)
})

   

.menu-left {
    flex: 1;
    padding: 0 8px;
    border-right: none;
    background: none;
}
.menu-left:deep(.el-menu),
.menu-left:deep(.el-sub-menu__title:hover) {
    background: none;
}
.menu-left:deep(.el-menu-item),
.menu-left:deep(.el-sub-menu__title) {
    height: 36px;
    margin-bottom: 4px;
    border-radius: 4px;
    color: var(--text-main-color) !important;
}
.menu-left:deep(.el-menu-item:hover .icon),
.menu-left:deep(.el-menu-item.is-active .icon) {
    filter: invert(100%);
    -webkit-filter: invert(100%);
}
.menu-left:deep(.el-menu-item:hover),
.menu-left:deep(.el-menu-item.is-active) {
    color: #ffffff !important;
    background-color: #eecece;
}

7.组件LeftSubMenu.vue的代码

    
        
            
                
                    
                
                {{ item.meta.title }}
            
            
        
        
            
                
                
                    
                
                {{ item.meta.title }}
            
        
    

   

import LeftSubMenu from "./LeftSubMenu.vue";
import { computed, onMounted } from "vue";
import { useRouter } from "vue-router";
const props = defineProps({
    menuData: {
        type: Array,
        default: [],
    },
});
onMounted(() => {
    console.log(props.menuData, "Item打印数据");
});
const curRoute = computed(() => {
    const router = useRouter();
    const { path } = router.currentRoute.value;
    return path;
});

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

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


免责声明
1、本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明。
2、本网站转载文章仅为传播更多信息之目的,凡在本网站出现的信息,均仅供参考。本网站将尽力确保所
提供信息的准确性及可靠性,但不保证信息的正确性和完整性,且不对因信息的不正确或遗漏导致的任何
损失或损害承担责任。
3、任何透过本网站网页而链接及得到的资讯、产品及服务,本网站概不负责,亦不负任何法律责任。
4、本网站所刊发、转载的文章,其版权均归原作者所有,如其他媒体、网站或个人从本网下载使用,请在
转载有关文章时务必尊重该文章的著作权,保留本网注明的“稿件来源”,并白负版权等法律责任。

手机扫描二维码访问

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,1705人围观)

还没有评论,来说两句吧...

目录[+]