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

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

<script setup>
import { RouterView ,useRouter} from 'vue-router';
import AsideMenu from '@/components/AsideMenu.vue'
const router = useRouter()
const logout = ()=>{
  localStorage.removeItem('token')
  router.replace('/login')
}
</script>
<template>
    <div class="common-layout">
      <el-container style="height: 100vh;">
        <el-aside width="200px">
            <AsideMenu></AsideMenu>
        </el-aside>
        <el-main>
          <div>
            <el-button @click="logout">推出登陆</el-button>
          </div>
            <RouterView />
        </el-main>
      </el-container>
    </div>
  </template>

6.组件AsideMenu.vue的代码:

<template>
    <el-menu router :default-active="$route.path" :class="'menu-left'" :default-openeds="openedsArr" text-color="#fff">
        <LeftSubMenu :menuData="treeMenu"></LeftSubMenu>
    </el-menu>
</template>
   
<script setup>
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)
})

</script>
   

<style scoped>
.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;
}
</style>

7.组件LeftSubMenu.vue的代码

<template>
    <template v-for="item in props.menuData">
        <el-sub-menu :key="item.path" v-if="item.children && item.children.length > 0" :index="item.path">

            <template #title>
                <el-icon>
                    <component :is="item.icon"></component>
                </el-icon>
                <span>{{ item.meta.title }}</span>
            </template>
            <LeftSubMenu :menuData="item.children"></LeftSubMenu>
        </el-sub-menu>


        <el-menu-item :key="item.id" v-else :index="item.path" :disabled="item.disabled">
            <template #title>
                <!-- <img class="icon pd-r-10" :src="item.icon" /> -->
                <el-icon>
                    <component :is="item.icon"></component>
                </el-icon>
                <span>{{ item.meta.title }}</span>
            </template>
        </el-menu-item>


    </template>
</template>
   
<script setup>
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;
});
</script>

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

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

GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐