vue3后台管理系统权限路由的实现
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue
免费下载资源
·
最近做管理系统的时候,需要实现不同用户登陆所展示的菜单不同,查了不少帖子,总结下实现的步骤:
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 个月前
更多推荐
已为社区贡献2条内容
所有评论(0)