当我们开发的系统涉及多权限的情况下,就需要对菜单进行分权限展示,对于管理员A可以展示用户数据页面,但不能展示经营盈亏页面,对管理员B可以展示经营盈亏页面,不能展示用户数据页面。
那么对于我们来说就需要对路由进行隐藏,但vue最常用的静态路由很难实现这种情况,即便是将菜单栏实现了菜单隐藏,但由于静态路由还是存在的,所以当用户在得知路由的情况下,可以在导航栏手动输入路由进行跳转。虽然这种情况可以使用路由守卫进行拦截,但当权限划分过于细腻后,编写的路由守卫将会过于复杂,冗余;所以更为适用的则是动态路由。
动态路由的优点便是他完全是根据后台所返回的路由进行载入,即便前端存在这个页面,但因为该页面的路由并未载入,所以无法访问这个页面。
同时联动递归展示的菜单组件可以做到菜单隐藏和路由隐藏两个功能。
在使用我们的动态路由时,对于原本的router下的index.js文件,我们只用于保存静态路由,例如,登录路由、注册路由这些不需要校验权限的路由
import Vue from 'vue'
import VueRouter from 'vue-router'
import menu from "../api/menu";
import stroe from "../store/index"
Vue.use(VueRouter)
const routes =[
{
path: '/login',
meta: { auth: false },
name: 'login',
component: () => import('../views/login')
},
{
path: '/register',
name: 'register',
component: () => import('../views/register')
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
注意router一定要定义成‘history’,
之后便是动态路由最核心的逻辑,从后端获取动态路由后组装好保存进路由中。利用router的addRouter方法添加新的路由,以此达到控制路由的目的.
创建一个routerUtil.js的文件,代码如下:
import menu from "../api/menu";
import router from "../router";
export function getChildrenPath () {
const routerList =[]
menu.getList().then(resp =>{ //调用后端接口获取路由列表
let menus =resp.data.data
menus.forEach(me =>{
setChild(me, routerList, '', '')
})
let rou = {
path: '/',
name: 'home',
component: () => import('../views/index'),
children: routerList
}
router.addRoute(rou)
})
}
function setChild(me, routerList, rootName, rootPath) {
rootName = rootName+'/'+me.name
rootPath = rootPath+'/'+me.path
if (me.children !=null && me.children != [] && me.children.length>0){
//如果有下层
me.children.forEach(node =>{
setChild(node, routerList, rootName,rootPath)
})
}else{
//没有下层则说明这是一个路由
let rou = {
name: rootName,
path: rootPath,
component: () =>import('@/views' + rootPath)
}
routerList.push(rou)
}
}
这里要注意的是你的路由一定要与你views下的文件名相对应,例如用户数据展示列表,路由为 user/userList
那么,views文件夹下的就是 user/userList.vue 或者 user/userList/index.vue
如下图
当我们的工具方法写完之后,便是调用的地方,我是在App.vue中进行的调用,能够很好的将动态路由载入,如下:
这是对保存的token进行判断,只有有token时才会载入路由,这么做的原因便是只有登录用户后才会载入动态路由,没有登录的情况下这里不会进行载入,以此降低了一部分系统的资源使用。
上面的都是在前端代码中的操作,由于我们动态路由需要后端的支持,所以在这里写一下后端所需要做到的事情。
首先是用来存储路由的数据库,这个数据库不单单是作为路由使用,同时也是动态菜单栏,所以虽然字段简单,但却又十分重要。
对应的数据库字段名如下:
后端接口传递的数据树结构组装方法就不在此过多赘述了,传递过来的数据结构如下:
{
"code": 200,
"msg": "success",
"data": [
{
"id": "1",
"name": "账号模块",
"path": "user",
"pid": "-1",
"icon": "el-icon-menu",
"sort": 1,
"delFlag": 0,
"children": [
{
"id": "2",
"name": "账号列表",
"path": "userList",
"pid": "1",
"icon": "el-icon-user-solid",
"sort": 2,
"delFlag": 0,
"children": []
}
]
}
]
}
这段json,可以直接拿去测试代码
目前便完成了简单的前端动态路由,配合动态菜单更能体现效果。