使用Vue实现后台管理系统的动态路由以及侧边栏菜单
介绍及说明
1、背景介绍:最近因为公司的项目,对一个后台管理系统进行前端重构,原项目是SSM架构的前后端没有分离,前端用JSP和jQuery来写的,在完成第一期之后,我强烈要求前后端分离,并使用vue来组件化开发。所以经过几天的摸索完成了项目的整体搭建和基础建设。
2、项目要求:因为原先的项目的菜单都是后台来动态生成的,所以用vue来写也要从后台获取路由表,前端再处理成我们想要的路由格式,再完成侧边栏菜单;并且前端页面里有一个模块专门来管理生成菜单和权限(也就是前端自定义一些菜单信息传给后端,后端把数据存到数据库,并根据角色权限处理完数据再返回路由表给前端,前端就可以动态生成侧边栏菜单了)。
实现过程
首先本项目是基于vue-element-admin的后台管理模板( vue-element-admin),这个模板很多功能都有现成的,很方便,拉取下来之后就可以基于这个进行开发了,这个模板有很详细的文档说明( vue-element-admin使用文档),里面也有动态路由的集成方案,本项目选择的就是路由全部通过后端来生成,前端来自定义需要的路由。
步骤如下:
1、用户登录成功之后(登录的功能,模板里也写的很好,换成公司的登录接口就可以直接用),再根据用户名获取用户的权限,然后根据用户权限获取后端的路由数据:
1)权限处理和生成动态路由:src/permission.js文件
import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // 进度条
import 'nprogress/nprogress.css' // 进度条样式
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
// import { getRoutes } from './api/role'NProgress.configure({ showSpinner: false }) // NProgress Configurationconst whiteList = ['/login', '/auth-redirect'] // 没有重定向白名单router.beforeEach(async(to, from, next) => {// 开始进度条
NProgress.start()// 设置页面标题
document.title = getPageTitle(to.meta.title)// 确定用户是否已登录,获取token
const hasToken = getToken()if (hasToken) {if (to.path === '/login') {// 如果已登录,则重定向到主页next({ path: '/' })NProgress.done()} else {// 确定用户是否通过getInfo获得了他的权限角色const hasRoles = store.getters.roles && store.getters.roles.length > 0if (hasRoles) {next()} else {try {// 获取用户权限信息const { roles } = await store.dispatch('user/getInfo')// 根据角色生成可访问路由映射const accessRoutes = await store.dispatch('permission/generateRoutes', roles)// console.log(accessRoutes)// 动态添加可访问路由router.options.routes = router.options.routes.concat(accessRoutes)router.addRoutes(accessRoutes)// hack方法 以确保addRoutes是完整的next({ ...to, replace: true })// console.log(router)} catch (error) {// 删除令牌,进入登录页面重新登录await store.dispatch('user/resetToken')Message.error(error || 'Has Error')next(`/login?redirect=${to.path}`)NProgress.done()}}}
} else {/* 没有令牌*/if (whiteList.indexOf(to.path) !== -1) {// 去往免费的登录白名单next()} else {// 没有访问权限的其他页面被重定向到登录页面next(`/login?redirect=${to.path}`)NProgress.done()}
}
})router.afterEach(() => {// finish progress bar
NProgress.done()
})
2)获取用户权限的代码:src/store/modules/user.js
// 获取用户权限信息
getInfo({ commit, state }) {return new Promise((resolve, reject) => {getInfo(state.code).then(response => {const { data } = response// console.log(data)if (!data) {reject('验证失败,请重新登录.')}let roles = []roles = roles.concat(data.usrGroupcode)const name = data.userName// // 角色必须是非空数组if (!roles || roles.length <= 0) {reject('getInfo: 角色必须是非空数组!')}const avatar = data.userCodecommit('SET_NAME', name)commit('SET_ROLES', roles)commit('SET_CODE', avatar)const users = {roles: roles,introduction: '',code: avatar,name: name}// console.log(users)resolve(users)}).catch(error => {reject(error)})})
},
2、处理后端返回的路由信息并存到vuex里:src/store/modules/permission.js
import { constantRoutes } from '@/router'
import { getMenu } from '../../api/role'
import Layout from '@/layout'/*** 将后端content字段转成组件对象*/
function _import(file) {return () => import(`@/views/${file}/index.vue`)
}/*** 通过递归过滤异步路由表* @param routes asyncRoutes* @param roles*/
export function filterAsyncRoutes(routes) {const res = []// eslint-disable-next-line no-emptyfor (let i = 0; i < routes.length; i++) {res.push({path: routes[i].content === 'Layout' ? `/${routes[i].path}` : routes[i].path,component: routes[i].content === 'Layout' ? Layout : _import(routes[i].content),name: routes[i].path,meta: {title: routes[i].menuname,icon: routes[i].icon},children: routes[i].children && routes[i].children.length ? filterAsyncRoutes(routes[i].children) : []})}return res
}const state = {routes: constantRoutes,addRoutes: []
}const mutations = {SET_ROUTES: (state, routes) => {state.addRoutes = routesstate.routes = constantRoutes.concat(routes)}
}const actions = {generateRoutes({ commit }, roles) {return new Promise((resolve, reject) => {let accessedRouteslet asyncRoutes = []getMenu(roles[0]).then(res => {if (res.msg === 'SUCCESS') {asyncRoutes = res.data} else {asyncRoutes = []}// console.log(asyncRoutes)accessedRoutes = filterAsyncRoutes(asyncRoutes)// 最后添加const unfound = { path: '*', redirect: '/404', hidden: true }accessedRoutes.push(unfound)// console.log(accessedRoutes)// console.log('store:accessedRoutes')commit('SET_ROUTES', accessedRoutes)resolve(accessedRoutes)}).catch(error => {reject(error)})})}
}export default {namespaced: true,state,mutations,actions
}
基础路由和统一路由:src/router/index.js
export const constantRoutes = [{path: '/redirect',component: Layout,hidden: true,children: [{path: '/redirect/:path*',component: () => import('@/views/redirect/index')}]},{path: '/login',component: () => import('@/views/login/index'),hidden: true},{path: '/auth-redirect',component: () => import('@/views/login/auth-redirect'),hidden: true},{path: '/404',component: () => import('@/views/error-page/404'),hidden: true},{path: '/401',component: () => import('@/views/error-page/401'),hidden: true},{path: '/',component: Layout,redirect: '/dashboard',name: 'home',meta: { title: '首页', affix: true },hidden: true,children: [{path: 'dashboard',component: () => import('@/views/dashboard'),hidden: true}]}]
3、然后再通过递归生成侧边栏菜单:src/layout
这个时候打印路由信息是可以得到正常的路由表信息;根据路由表生成侧边栏:
this.$router.options.routes 可以获取路由表信息,具体逻辑vue-element-admin模板里有现成的,这里就不解释了。
最后说一下后端返回的数据结构:
[{applicationid: 1035
children: [ //子节点,结构和当前一样0:{applicationid: 1035children: [0: {applicationid: 1035children: nullcontent: "system/system-management/menu"formid: 101100formtype: 1icon: ""inactived: 1memo: "EAM"menuid: 101100menuname: "菜单管理"parentmenuid: 101000parentrowid: "01KBGO"path: "menu"roles: ""rowid: "01KBGP"seq: 101100treecontrol: "01KBGP01KBGO01KBG9"}]content: "system/system-management"formid: 101000formtype: 1icon: ""inactived: 1memo: "EAM"menuid: 101000menuname: "系统设置"parentmenuid: 100000parentrowid: "01KBG9"path: "system-management"roles: ""rowid: "01KBGO"seq: 101000treecontrol: "01KBGO01KBG9"}
]
content: "Layout" //对应组件的名称
formid: 100000
formtype: 1
icon: "" //菜单的图标
inactived: 1 //是否启用
memo: "EAM"
menuid: 100000 //菜单的id
menuname: "系统管理" //菜单的名称
parentmenuid: null //父级菜单id
parentrowid: ""
path: "system" //路由
roles: ""
rowid: "01KBG9"
seq: 100000 //排序
treecontrol: "01KBG9"
}]
使用Vue实现后台管理系统的动态路由以及侧边栏菜单相关推荐
- 【前端】Vue+Element UI案例:通用后台管理系统-登陆不同用户显示不同菜单、动态添加路由
文章目录 目标 代码 0.动态地显示菜单:store 1.动态注册路由 2.解决刷新后摆平问题 总代码 本篇修改的代码文件 tab.js 参考视频: VUE项目,VUE项目实战,vue后台管理系统,前 ...
- SpringBoot实现分页查询——基于SpringBoot和Vue的后台管理系统项目系列博客(七)
系列文章目录 系统功能演示--基于SpringBoot和Vue的后台管理系统项目系列博客(一) Vue2安装并集成ElementUI--基于SpringBoot和Vue的后台管理系统项目系列博客(二) ...
- SpringBoot实现代码生成器——基于SpringBoot和Vue的后台管理系统项目系列博客(十)
系列文章目录 系统功能演示--基于SpringBoot和Vue的后台管理系统项目系列博客(一) Vue2安装并集成ElementUI--基于SpringBoot和Vue的后台管理系统项目系列博客(二) ...
- SpringBoot实现1对1、1对多、多对多关联查询——基于SpringBoot和Vue的后台管理系统项目系列博客(十八)
系列文章目录 系统功能演示--基于SpringBoot和Vue的后台管理系统项目系列博客(一) Vue2安装并集成ElementUI--基于SpringBoot和Vue的后台管理系统项目系列博客(二) ...
- SpringBoot和Vue集成Markdown和多级评论——基于SpringBoot和Vue的后台管理系统项目系列博客(二十三)
系列文章目录 系统功能演示--基于SpringBoot和Vue的后台管理系统项目系列博客(一) Vue2安装并集成ElementUI--基于SpringBoot和Vue的后台管理系统项目系列博客(二) ...
- Vue + ElementUI 后台管理系统实现主题风格切换
一.目的 此次写作内容是在我之前发布一篇文章的基础上进行新增的. 上一篇文章:Vue + ElementUI 后台管理系统实现顶部一级菜单栏,左侧二级菜单栏_无解的菜鸟晖的博客-CSDN博客 这次要实 ...
- VUE项目后台管理系统(四)左边菜单动态展示,不仅可以折叠,而且点击不同的菜单,右边展示不同的页面
目录 左边菜单动态的展示 左边菜单的属性介绍 遍历菜单 左边菜单折叠效果 不同的菜单右面展示不同的页面 左边菜单动态的展示 首先后端的接口要返回菜单的list集合,是json格式,我使用的是pytho ...
- 结合 服务器+后端+前端,完成 vue项目 后台管理系统
目录 以上是项目的服务器php.后端.前端.已经可以正常运行 一 登录: 登录页进度条:戳这里Vue项目电商后台管理系统 nprogress--进度条_活在风浪里的博客-CSDN博客 二 侧导航 三 ...
- 【Vue】后台管理系统
O 项目说明 1.脚手架 vite vue-cli ==> webpack 2.vite脚手架使用 官网:https://vitejs.cn/ Vue3 vite官网:https://cn.vi ...
最新文章
- 如何更好的创建Java对象
- CentOS 6.x 播放 mp3 音乐 —— 成功
- python零基础有用吗-10天搞定Python,告诉你有什么用?
- 信噪比与误码率的计算
- 深度探索va_start、va_arg、va_end
- RecyclerView 显示不全的问题.
- ee2prom擦除 c语言,浮点数在E2PROM中的存取方法.doc
- 刘庆敏 博客linux,Linux内核源码分析--zImage出生实录(Linux-3.0 ARMv7)
- redis队列(list)
- SRM 578 DIV 2
- php删除对象中的一个数组,PHP:从数组中删除对象
- Tableau可视化学习笔记:day03-04
- matplotlib tricks —— 平滑方法
- 互联网招聘数据分析处理与可视化
- 梦三国解析服务器spl文件头失败怎么解决,梦三国手游野区BUFF点解析 野区BUFF怎么的打...
- Unity使用PhotoShop制作磨砂玻璃材质
- QT笔记——Qt动态属性 之 unpolish() 和 polish()
- 【优秀毕设V2.0】基于树莓派的OpenCV-Python摄像头人脸追踪及手势识别、网络地址推流及远程控制系统(多功能系统、含演示视频)
- 强化学习笔记-01强化学习介绍
- STL - emplace 与 push 的区别