目录
前言
一、项目介绍
1.开发环境
2.功能
3.项目运行截图
二、实现
1.动态路由如何实现
2.项目目录介绍
3.核心代码
4.坑和知识点
小结
最近在学权限相关的管理项目,前端用到了动态路由,就是根据用户角色显示不同的菜单,动态添加路由。说着好像很简单,但看了很多教程,也跟着教程写了很多代码,但最后都跑不通(很多原因,比如:版本问题,教程没有全部代码,只有核心代码片段等)。所以,我只能狠下心,写下这篇博客,方便自己总结,也为了避免大家踩坑。
废话不多说,直接附上项目下载地址:
gitee:https://gitee.com/wusupweilgy/springboot-vue.git
蓝奏云:https://wwp.lanzoup.com/iO74W0r6bcob
前端:vue2+element-ui组件
根据用户的账号密码,生成不同的菜单,动态添加路由
流程:
1)/views/Login.vue:登录(onSubmit方法)成功时,根据用户名密码区分角色,根据角色将不同路由和token写入vuex,dynamicRoutes.js中有两个路由模板,分别是user和admin,然后调用generateRoutes()方法向vue-router中动态添加路由
import {admin,user} from '@/router/dynamicRoutes'
...
onSubmit(formName) {
//为表单绑定验证功能
this.$refs [formName].validate((valid) => {
if (valid) {
if(this.form.username==="user"&&this.form.password==="user"){
store.commit('SET_MENULIST', user);
store.commit('SET_TOKEN', 'user');
}else if(this.form.username==="admin"&&this.form.password==="admin"){
store.commit('SET_MENULIST', admin);
store.commit('SET_TOKEN', 'admin');
}else{
this.$message.error("登录失败")
return
}
this.$message.success("登录成功")
generateRoutes()
this.$router.replace('/')
} else {
this.dialogVisible = true;
return false;
}
});
},
2)/store/index.js:vuex状态管理(配合sessionStorage)
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
token:'',
menuList:[],
isLoadRouters:false
},
getters: {
GET_TOKEN:state => {
state.token = sessionStorage.getItem("token")
return state.token
},
GET_MENULIST:state => {
state.menuList = JSON.parse(sessionStorage.getItem("menuList")||'[]')
return state.menuList
},
GET_ISLOADROUTERS:state=>{
return state.isLoadRouters
}
},
mutations: {
SET_TOKEN:(state,token)=>{
state.token = token
sessionStorage.setItem("token",token);
},
SET_MENULIST:(state,menuList)=>{
state.menuList = menuList
sessionStorage.setItem("menuList",JSON.stringify(menuList));
},
SET_ISLOADROUTERS:(state,isLoadRouters)=>{
state.isLoadRouters = isLoadRouters
}
},
})
3)/util/index.js:方法动态添加路由工具
import router from '../router'
import store from '@/store'
//动态添加路由
export function generateRoutes() {
const _asyncRoutes = store.getters.GET_MENULIST
if(_asyncRoutes==null)
return
_asyncRoutes.forEach(menu => {
if (menu.children) {
menu.children.forEach(m => {
let route = menuToRoute(m, menu.name);
if (route) {
router.addRoute("Home",route)
}
})
}
})
}
//将菜单转换成router可以识别的路由
const menuToRoute = (menu, parentName) => {
if (!menu.component) {
return null;
} else {
let route = {
name: menu.name,
path: menu.path,
meta: {
parentName: parentName
}
}
route.component = () => import('@/views/' + menu.component + '.vue');
return route;
}
}
4)/router/permission.js:前置路由守卫,判断是否登录和是否已经添加过路由
import router from "@/router/index"
import store from "@/store"
import {generateRoutes} from "@/util";
// 检查是否存在于免登陆白名单
function inWhiteList(toPath) {
const whiteList = ['/login', '/404']
const path = whiteList.find((value) => {
// 使用正则匹配
const reg = new RegExp('^' + value)
return reg.test(toPath)
})
return !!path
}
router.beforeEach((to, from, next) => {
console.group('%c%s', 'color:blue', `${new Date().getTime()} ${to.path} 的全局前置守卫----------`)
console.log('所有活跃的路由记录列表', router.getRoutes())
console.groupEnd()
const token = store.getters.GET_TOKEN
let isLoadRouters = store.state.isLoadRouters
if (inWhiteList(to.path)) {
next()
} else {
//用户已登录
if (token && JSON.stringify(store.getters.GET_MENULIST) !== '[]') {
if (isLoadRouters) {
// console.log('路由已添加,直接跳转到目标页面');
next()
} else {
//解决刷新页面空白
//console.log('重新加载路由,并跳转到目标页');
let menuList = store.getters.GET_MENULIST
store.commit('SET_ISLOADROUTERS', true)
//添加动态路由
generateRoutes(menuList)
next({...to, replace: true})
}
} else {
// console.log('无登录信息,跳转到登录页');
store.commit('SET_ISLOADROUTERS', false)
next(`/login`)
}
}
})
1)遇到的坑
这两个坑就已经卡了我很长时间了,更何况还有其他小坑(哭死我了)
用户点击退出后,需要重置路由,不然你添加过路由了,再通过addRoute()方法添加路由就会造成重复添加路由,浏览器的控制台会有警告,不重置也没事,就是看着有点不舒服。
// 重置路由
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher
}
2)学到的知识点
js语法:两个感叹号,将非布尔型变量转为布尔值
// 检查是否存在于免登陆白名单
function inWhiteList(toPath) {
const whiteList = ['/login', '/404']
const path = whiteList.find((value) => {
// 使用正则匹配
const reg = new RegExp('^' + value)
return reg.test(toPath)
})
return !!path
}
本文介绍了使用Vue实现动态路由。关于这个东西,我网上找的很多教程都不怎么靠谱,给我挖了很多坑,所以希望我的这篇教程可以帮助你,少走点弯路,快速掌握这技术,代码的下载地址在文章开头,记得npm install一下,就可以运行了。如果这篇文章有幸帮助到你,希望读者大大们可以给作者给个三连呀️️️