【Vue】 vue-element-admin 路由菜单配置
路由说明见官方文档:
https://panjiachen.gitee.io/vue-element-admin-site/zh/guide/essentials/router-and-nav.html
组件渲染的数据来源
这里先说明侧边栏组件获取的路由:
src\layout\components\Sidebar\index.vue
路由是通过这个permission_routers获取的
<template>
<div :class="{'has-logo':showLogo}">
<logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
:collapse="isCollapse"
:background-color="variables.menuBg"
:text-color="variables.menuText"
:unique-opened="false"
:active-text-color="variables.menuActiveText"
:collapse-transition="false"
mode="vertical"
>
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
</el-menu>
</el-scrollbar>
</div>
</template> <script>
import { mapGetters } from 'vuex'
import Logo from './Logo'
import SidebarItem from './SidebarItem'
import variables from '@/styles/variables.scss' export default {
components: { SidebarItem, Logo },
computed: {
...mapGetters([
'permission_routes',
'sidebar'
]),
activeMenu() {
const route = this.$route
const { meta, path } = route
// if set path, the sidebar will highlight the path you set
if (meta.activeMenu) {
return meta.activeMenu
}
return path
},
showLogo() {
return this.$store.state.settings.sidebarLogo
},
variables() {
return variables
},
isCollapse() {
return !this.sidebar.opened
}
}
}
</script>
访问到Gettter.js可以看到Vuex是区分了命名空间的,对应的空间是permission
const getters = {
sidebar: state => state.app.sidebar,
size: state => state.app.size,
device: state => state.app.device,
visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews,
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
introduction: state => state.user.introduction,
roles: state => state.user.roles,
// permission_routes: state => state.permission.routes,
permission_routes: state => state.menu.routes,
errorLogs: state => state.errorLog.logs
}
export default getters
所以说,默认是从permission模块里的routes获取的
如果我们新开的Vuex写路由获取逻辑,这里不改的话就拿不到我们自己获取的路由了
路由权限控制
在main.js下面的permission里面:
每次跳转路由,都要从VueX拿令牌,判断用户是否有效
自己定义校验规则 和 路由获取规则即可,
这段参考Open-his来做的,路由还是前端配置,控制只展示哪些,交给后端来完成
import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title' NProgress.configure({ showSpinner: false }) // NProgress Configuration /**
* no redirect whitelist
* 白名单,没有权限控制的路由地址
* @type {string[]}
*/
const whiteList = ['/login', '/auth-redirect'] /**
* 在路由跳转之前,勾子函数的控制
*/
router.beforeEach(async(to, from, next) => {
/* 启动进度条 start progress bar */
NProgress.start() /* 设置系统标签文本信息 set page title */
document.title = getPageTitle(to.meta.title) /* 从Cookie里面提取令牌 determine whether the user has logged in */
const hasToken = getToken() /* 令牌存在 */
if (hasToken) {
/* 访问登录页时直接放行 */
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({ path: '/' })
NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
} else {
/**
* 判断当前用户的角色集合是否存在
* determine whether the user has obtained his permission roles through getInfo
* @type {any}
*/
// const hasRoles = store.getters.roles && store.getters.roles.length > 0
/* 存在则放行路由 */ // 确定用户是否已通过getInfo获得其用户
const hasName = !!store.getters.name if (hasName) {
next()
} else {
/* 没有则重新获取用户信息 */
try {
/**
* // get user info
* // note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
* 根据令牌重新获取用户信息,只要角色集合
*/
const { menus } = await store.dispatch('user/getInfo') /**
* generate accessible routes map based on roles
* 创建可访问的路由表
* @type {any}
*/
// const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
const accessRoutes = await store.dispatch('menu/getAccessMenus', menus) /**
* dynamically add accessible routes
* 动态添加路由
*/
router.addRoutes(accessRoutes) /**
* 如果用户状态持续,保持路由不会丢掉历史记录
* // hack method to ensure that addRoutes is complete
* // set the replace: true, so the navigation will not leave a history record
*/
next({ ...to, replace: true })
} catch (error) {
/**
* 如果用户信息无法获取,重定向,要求用户重新登录
* remove token and go to login page to re-login
*/
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}
} else {
/* 如果没有令牌,检查是否是白名单的路由 has no token*/ if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next()
} else {
/* 没有权限,也不是白名单,重定向到登录页面 */
// other pages that do not have permission to access are redirected to the login page.
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}) /* 每次跳转之后的回调勾子 */
router.afterEach(() => {
/* finish progress bar 进度条加载完成 */
NProgress.done()
})
路由获取规则Menu.js
import { asyncRoutes, constantRoutes, lastRoute } from '@/router/index'
const state = {
routes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = routes
}
}
/**
* 递归路由集合,和用户的菜单进行比较,符合则打开,反之关闭
* @param routes
* @param srvMenus
*/
function generateMenus(routes, srvMenus) {
for (let i = 0; i < routes.length; i++) {
const routeItem = routes[i]
let showItem = false
for (let j = 0; j < srvMenus.length; j++) {
const srvItem = srvMenus[j]
// 前后端数据通过 serPath 属性来匹配
if (routeItem.name !== undefined && routeItem.name === srvItem['menuRoute'] && srvItem['isShow'] === true) {
showItem = true
routes[i]['hidden'] = false
break
}
}
if (showItem === false) {
routes[i]['hidden'] = true
}
if (routeItem['children'] !== undefined && routeItem['children'].length > 0) {
generateMenus(routes[i]['children'], srvMenus)
}
}
}
const actions = {
getAccessMenus({ commit }, menus) {
return new Promise(resolve => {
const pushRouter = asyncRoutes
generateMenus(pushRouter, menus)
const routeArr = []
console.log(constantRoutes)
routeArr.push(...constantRoutes)
routeArr.push(...pushRouter)
routeArr.push(...lastRoute)
commit('SET_ROUTES', routeArr)
console.log(routeArr)
/* 返回全部匹配的路由 */
resolve(routeArr)
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
前端路由表配置:
我想弄三层菜单,需要第二层再单开组件放路由才可以,这个可以查看文档说明
https://panjiachen.github.io/vue-element-admin-site/zh/guide/essentials/router-and-nav.html#侧边栏

这里我就只放异步路由的配置,常量路由是所有人都能看的,没啥可表达的
/**
* 异步路由,根据用户的角色集合动态加载
* asyncRoutes
* the routes that need to be dynamically loaded based on user roles
*/
export const asyncRoutes = [
{
path: '/system',
component: Layout,
redirect: 'noRedirect',
name: '/system',
alwaysShow: true,
meta: { title: '系统管理', icon: 'lock' },
children: [
{
path: 'rbac',
component: () => import('@/views/tt-server/system/rbac/index'),
name: '/system/rbac',
meta: { title: '权限维护', icon: 'lock' },
children: [
{
path: 'user-info',
component: () => import('@/views/tt-server/system/rbac/user-info/index'),
name: '/system/rbac/user-info',
meta: { title: '用户管理', icon: 'edit' }
},
{
path: 'role-info',
component: () => import('@/views/tt-server/system/rbac/role-info/index'),
name: '/system/rbac/role-info',
meta: { title: '角色管理', icon: 'edit' }
},
{
path: 'menu-info',
component: () => import('@/views/tt-server/system/rbac/menu-info/index'),
name: '/system/rbac/menu-info',
meta: { title: '菜单管理', icon: 'edit' }
},
{
path: 'privilege-info',
component: () => import('@/views/tt-server/system/rbac/privilege-info/index'),
name: '/system/rbac/privilege-info',
meta: { title: '权限管理', icon: 'edit' }
}
]
},
{
path: 'common',
component: () => import('@/views/tt-server/system/common/index'),
name: '/system/common',
alwaysShow: true,
meta: { title: '通用管理', icon: 'lock' },
children: [
{
path: 'dict-info',
component: () => import('@/views/tt-server/system/common/dict-info/index'),
name: '/system/common/dict-info',
meta: { title: '字典管理', icon: 'edit' }
},
{
path: 'area-info',
component: () => import('@/views/tt-server/system/common/area-info/index'),
name: '/system/common/area-info',
meta: { title: '区域管理', icon: 'edit' }
},
{
path: 'system-param',
component: () => import('@/views/tt-server/system/common/system-param/index'),
name: '/system/common/system-param',
meta: { title: '系统参数', icon: 'edit' }
},
{
path: 'system-log',
component: () => import('@/views/tt-server/system/common/system-log/index'),
name: '/system/common/system-log',
meta: { title: '系统日志', icon: 'edit' }
}
]
}
]
}
]
后台数据设计:
表结构
CREATE TABLE `sys_menu` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '菜单主键',
`app_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '应用编号',
`menu_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单名称',
`menu_value` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单值',
`menu_icon` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单图标',
`menu_level` int NOT NULL DEFAULT '1' COMMENT '菜单层级',
`menu_type` varchar(12) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '菜单类型',
`menu_sort` int NOT NULL COMMENT '菜单排序',
`menu_route` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '菜单路由',
`is_show` tinyint(1) DEFAULT '1' COMMENT '是否展示 1展示 0隐藏',
`menu_path` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单主键路径',
`parent_id` int NOT NULL DEFAULT '0' COMMENT '父级菜单,顶级菜单默认为0',
`creator` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`updater` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100200401 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统菜单表';
菜单记录:
【菜单路由】和【是否展示】是前端路由展示的判断条件
mysql> SELECT * FROM sys_menu;
+-----------+-----------+-----------+--------------+-----------+------------+-----------+-----------+-----------------------------+---------+---------------------------------+-----------+---------+---------------------+---------+---------------------+
| id | app_code | menu_name | menu_value | menu_icon | menu_level | menu_type | menu_sort | menu_route | is_show | menu_path | parent_id | creator | create_time | updater | update_time |
+-----------+-----------+-----------+--------------+-----------+------------+-----------+-----------+-----------------------------+---------+---------------------------------+-----------+---------+---------------------+---------+---------------------+
| 100000000 | tt-server | 系统管理 | system | | 1 | Directory | 1 | /system | 1 | 0,100000000 | 0 | admin | 2022-12-07 23:46:49 | admin | 2022-12-07 23:46:51 |
| 100100000 | tt-server | 权限维护 | privileges | | 2 | Directory | 1 | /system/rbac | 1 | 0,100000000,100100000 | 100000000 | admin | 2022-12-07 23:41:14 | admin | 2022-12-07 23:41:16 |
| 100100100 | tt-server | 用户管理 | user-info | | 3 | Function | 1 | /system/rbac/user-info | 1 | 0,100000000,100100000,100100100 | 100100000 | admin | 2022-12-07 23:44:12 | admin | 2022-12-07 23:44:12 |
| 100100200 | tt-server | 角色管理 | role-info | | 3 | Function | 2 | /system/rbac/role-info | 1 | 0,100000000,100100000,100100200 | 100100000 | admin | 2022-12-07 23:44:12 | admin | 2022-12-07 23:44:12 |
| 100100300 | tt-server | 菜单管理 | menu-info | | 3 | Function | 3 | /system/rbac/menu-info | 1 | 0,100000000,100100000,100100300 | 100100000 | admin | 2022-12-07 23:44:12 | admin | 2022-12-07 23:44:12 |
| 100100400 | tt-server | 权限管理 | permit-info | | 3 | Function | 4 | /system/rbac/privilege-info | 1 | 0,100000000,100100000,100100400 | 100100000 | admin | 2022-12-07 23:44:12 | admin | 2022-12-07 23:44:12 |
| 100200000 | tt-server | 通用管理 | common | | 2 | Directory | 2 | /system/common | 1 | 0,100000000,100200000 | 100000000 | admin | 2022-12-07 23:42:03 | admin | 2022-12-07 23:42:03 |
| 100200100 | tt-server | 字典管理 | dict-info | | 3 | Function | 1 | /system/common/dict-info | 1 | 0,100000000,100200000,100200100 | 100200000 | admin | 2022-12-07 23:44:12 | admin | 2022-12-07 23:44:12 |
| 100200200 | tt-server | 行政区域 | area-info | | 3 | Function | 2 | /system/common/area-info | 1 | 0,100000000,100200000,100200200 | 100200000 | admin | 2022-12-07 23:44:12 | admin | 2022-12-07 23:44:12 |
| 100200300 | tt-server | 系统参数 | system-param | | 3 | Function | 3 | /system/common/system-param | 1 | 0,100000000,100200000,100200300 | 100200000 | admin | 2022-12-07 23:44:12 | admin | 2022-12-07 23:44:12 |
| 100200400 | tt-server | 系统日志 | system-log | | 3 | Function | 4 | /system/common/system-log | 1 | 0,100000000,100200000,100200400 | 100200000 | admin | 2022-12-07 23:44:12 | admin | 2022-12-07 23:44:12 |
+-----------+-----------+-----------+--------------+-----------+------------+-----------+-----------+-----------------------------+---------+---------------------------------+-----------+---------+---------------------+---------+---------------------+
展示效果

【Vue】 vue-element-admin 路由菜单配置的更多相关文章
- vue+npm+Element插件+路由
首先安装node.js 之后使用管理员输入命令 然后,就可以使用 npm 命令安装了: npm install -g @vue/cli安装完后,打开命令行窗口,会有一个 vue 命令:vue -v v ...
- Vue - 项目配置 ( element , 安装路由 , 创建路由 )
1,安装element : vue add element 2,安装路由 : vue add router 3,创建路由的过程 : (1) 新建 vu ...
- 【vue】iView-admin2.0动态菜单路由
vue项目实现动态路由有俩种方式 一.前端在routers中写好--所有--路由表 <前端控制路由>,登录时根据用户的角色权限来动态的显示菜单路由 二.前端通过调用接口请求拿到当前用户-- ...
- 【vue】iView-admin2.0动态菜单路由【版2】
依照iView-admin2.0动态菜单路由[版1] 归纳几个节点动态路由获取方式2 ——> easymock假数据 ——> 数据转组件处理.addRoutes ——> localS ...
- vue路由的配置
一.准备工作 1安装vue-cli npm install vue-cli -g 2检查是否安装成功 vue -V(大写V) 3初始化一个新的项目 vue init webpack vue-dem ...
- Vue 路由模块化配置
博客地址:https://ainyi.com/77 企业运营后台页面很多,路由如若不区分模块化配置,所有路由挤在同一个文件将不好维护,所以路由的配置也要模块化 分享两个解决方案 -- Vue 路由配置 ...
- vue项目中router路由配置
介绍 路由:控制组件之间的跳转,不会实现请求.不用页面刷新,直接跳转-切换组件>>> 安装 本地环境安装路由插件vue-router: cnpm install vue-rou ...
- Vue+elementUI 自定义动态数据菜单导航组件实现展开收缩+路由跳转router-view渲染数据 路由跳转到同一个页面带参数ID 自动刷新数据
准备:导入ElementUI 看官网教程 数据准备:JSON数据转换成树状 参考文章: JS实现 JSON扁平数据转换树状数据 后台我拿的数据是这样的格式: [ {id:1 , parentId: 0 ...
- 神奇!这款 Vue 后台框架居然不用手动配置路由
前言 做 Vue 开发脱离不了路由,尤其是中大型项目,页面多且杂,在配置路由的时候总是会变得逐渐暴躁,因为费时,并且又没有什么太多技术含量,总觉得是在浪费时间. 另外如果接手了别人的项目,当业务有变更 ...
- Vue路由相关配置
什么是路由? 1.在以前页面跳转使用的是超链接a标签或者js location.href,而路由是跳转切换组件的跳转方式 2.路由就是监听url的改变并提供相对应的组件用于展示 3.vue-route ...
随机推荐
- js 求任意两数之间的和
知识点:函数的传参,函数的返回值 函数的传参 函数的参数包括以下两种类型: 1.形参:在定义函数时,声明的参数变量仅在函数内部可见: 2.实参:在调用函数时,实际传入的值. 示例 我们在定义函数的时候 ...
- tab切换之循环遍历
<style> *{ margin: 0; padding:0; } ul,ol,li{ ...
- vue导航固定 吸顶效果
吸顶效果 如何得到滚动条滚动的距离,document.documentElement.scrollTop 通过onscroll事件来完成滚动事件监听,达到吸顶值后,进行样式更换
- 图形库使用 Direct3d
1 里面的数学 矩阵是三角函数组合出来的 旋转的时候 xy 两个变量距离变 第三轴被影响角度 2视锥 远近四棱锥双剪切平面 3 三维点 A点 B点 C点 确定三位坐标 ,初始坐标是坐标中中心值 x,y ...
- FlashDuty Changelog 2023-09-21 | 自定义字段和开发者中心
FlashDuty:一站式告警响应平台,前往此地址免费体验! 自定义字段 FlashDuty 已支持接入大部分常见的告警系统,我们将推送内容中的大部分信息放到了 Lables 进行展示.尽管如此,我们 ...
- 如何生成war包
pom.xml <packaging>war</packaging> 引入tomcat <dependency> <groupId>org.spring ...
- 用typescript实现一个event bus
一个简单event bus的实现 发布订阅者模式 type emitKey = number | string | symbol; type func = (...args: any) => v ...
- idea编译报错 静态Map初始化报错java.lang.ExceptionInInitializerError
idea编译报错 静态Map初始化报错java.lang.ExceptionInInitializerError package cc.mrbird.utils; import java.util.H ...
- 【Playwright+Python】系列教程(一)环境搭建及脚本录制
前言 看到这个文章,有的同学会说: 六哥,你为啥不早早就写完python系列的文章. 因为有徒弟需要吧,如果你也想学自学,那这篇文章,可以说是我们结缘一起学习的开始吧! 如果对你有用,建议收藏和转发! ...
- InvalidOperationException Cannot modify ServiceCollection after application is built .Net6 异常
背景 我用了一个叫Unchase.Swashbuckle.AspNetCore.Extensions的库来加强Swagger的文档,我一般写法是这样的: builder.Services.AddSwa ...