💂 个人网站:
【紫陌】【笔记分享网】
💅 想寻找共同学习交流、共同成长的伙伴,
请点击【前端学习交流群】
登录的接口请求的三个内容:
1. token
2. 用户信息、角色信息
3. 菜单信息
第一种:基于角色Role的动态路由管理
(不推荐,但市场用的比较多)
首先列出枚举每个角色对应几个路由,然后根据用户登录的角色遍历枚举出来的角色动态注册对应的路由
const roles = {
admin:['所有路由'],
'经理':['10个路由'],
'运营':['5个路由'],
'前台':['2个路由']
'新增一个角色':[xxx] ===>改代码重新发布版本
}
这种做法一个弊端:每添加一个角色,都要手动添加代码key:value。最后前端又要发布新的版本
(有解决方案如下)
这种方法大致流程如下:
登录:登录验证通过之后后台会返回一个
token
给前端,前端会保存在vuex和本地(防止刷新丢失登录状态),然后拿
token
去后台请求一个userInfo的接口获取用户信息(用户名,权限信息等等)
权限验证:通过token获取用户role信息,然后根据用户role算出对应应有权限信息的路由,最后用router.addRotes动态挂载计算出的路由。
代码的实现:
根据token拿到用户信息(权限信息)
这里代码过于简单就不写了,就是请求后台的数据而已。
请求回来的数据保存在Vuex当中(actions发请求—-mutations传数据给state,过程不书写了)
//箭头函数
const getDefaultState = () => {
return {
//获取token
token: getToken(),
//存储用户名
name: '',
//存储用户头像
avatar: '',
//服务器返回的菜单信息【根据不同的角色:返回的标记信息,数组里面的元素是字符串】
routes: [],
//角色信息
roles: [],
//按钮权限的信息
buttons: [],
}
}
vuex查看数据:保存成功
Router中路由的拆分(现在路由是全部注册好的,写死的,不管什么用户看的都是一样的页面。)
分为三类路由:
-
常量路由,不管什么角色都可以看得路由
-
任意路由:路径出错的时候重定向404
-
异步路由:不同角色需要过滤选出路由(根据后台的返回的角色计算出对呀的路由)
store/user.js中对比路由
首先要在state定一个计算好的路由变量
resultAsyncRoutes:[]
和一个最终合并展示路由变量
resultAllRputes:[]
在获取用户信息的时候异步路由和服务器返回的路由进行对比。commit要提交对比好的路由,所有写一个对比路由函数。
computedAsyncRoutes()函数第一个参数是异步路由,第二个是服务器返回的路由。
在actions外面定义一个对比路由的
computedAsyncRoutes
函数:
//定义一个函数:两个数组进行对比,对比出当前用户到底显示哪些异步路由
const computedAsyncRoutes = (asyncRoutes, routes) => {
//过滤出当前用户【超级管理|普通员工】需要展示的异步路由
return asyncRoutes.filter(item => {
//数组当中没有这个元素返回索引值-1,如果有这个元素返回的索引值一定不是-1
if (routes.indexOf(item.name) != -1) {
//递归:别忘记还有2、3、4、5、6级路由
if (item.children && item.children.length) {
item.children = computedAsyncRoutes(item.children, routes);
}
return true;
}
})
}
commit的时候对比好路由(需要深拷贝一下,不然对比后数据影响原数据)
打印异步路由和服务器返回的路由:
然后在mutations中合并路由(计算出来的异步路由,常量路由,任意路由进行合并)用router.addRotes动态挂载计算出的路由。
根据计算出路由展示菜单
目前为止路由都准备好了,但是侧边栏展示还是常量路由,侧边栏应该遍历vuex合并好的路由resultAllRputes
在Sidebar组件中:
这样侧边栏就这根据权限动态展示了。
按钮权限:
菜单权限:不同的用户(角色),能操作、能观看的菜单是不同的。
按钮的权限:不同的用户(角色),有的用户的是可见按钮、当然有的用户不可见。
实现方式也比较简单:根据后台返回button是否有这个按钮的权限值。
用v-if去判断后台返回
buttons
是否包含该按钮的权限,没有就不显示。
<template>
<div>
<el-button type="primary" v-if="$store.state.user.buttons.indexOf('btn.Add1')!=-1">添加按钮1</el-button>
<el-button type="primary" v-if="$store.state.user.buttons.indexOf('btn.Add2')!=-1">添加按钮2</el-button>
</div>
</template>
第二种:基于菜单Menu的动态路由管理
(推荐)
我这里是从0搭建的,很多细节需要自己处理,看起来比上面的方法麻烦其实不是这样的,上面是使用vue-admin很多细节作者已经处理好了,我这里需要自己处理,也更好的理解各种细节问题。
-
userMenus =>动态展示菜单
-
用户管理 —-商品管理—-角色管理等等这些路由
模块映射成一个对象
然后和后端返回这个角色的菜单信息进行对比,然后用Router.addRotes的API动态注册路由。
大致流程:(Vue3+TS+pinia实现)
这里的后台和上面的返回格式不一样,问题也不大。首页还是拿到token,用token拿用户信息,用户信息中有用户id,那个用户id去后台拿菜单信息。
后台返回的菜单信息:
然后对路由进行划分:
对比一下他们的路由信息:
然后进行路由对比,对比好就动态注册路由,要点击登录前就要计算好路由,也就是说push到首页就要算好路由,所有在login中actions进行对比,但是这个逻辑比较多,为了方便管理对比路由函数写在utils
在utils中:
这里用了两个for循环因为这里明确知道两次目录,要是children两层以上可以用递归
在login中actions使用:
计算好的路由放到routes数组中,然后forEach遍历用router.addRoute动态添加路由(addRoute第一个参数是目标路由,第二个参数就是路由信息,代码上的意思就是将遍历出来的路由信息添加main的
children
下面)
目前效果可以做到点击菜单路由也可以跟着改变了
但是目前有一个问题就是,我注册权限路由是pinia的actions在点击登录按钮的回调进行注册的,现在当我刷新的时候这些路由就访问不到了,只能访问不用权限的路由,为什么会这样?
因为刷新不会重新加载pinia的actions的登录的回调,只有点击登录才会执行,解决办法就是刷新让这个回调重新执行一遍。具体实现如下:
-
在actions在定一个函数
函数定义好了,要让他刷新执行一遍,需要在main执行(顺序比较重要批念必须先加载,然后再动态注册权限路由,最后加载router)
第一个页面的匹配方法:
现在做一个小细活,就是登录完立刻重定向到第一个页面(这个需要动态的,不是每个角色第一个页面都是一样的)
在那个utils中的
mapMenusToRouters
函数增加两句代码
然后再router里面的前置守卫使用
根据path匹配menu
现在点击部门管理刷新会跳转到一点页面,我们要的还是留在部门管理这个路由
在nav-menu组件组件中:
计算出defaultActive
在utils写工具函数
大致流程就是这样了。
文章有帮助到您帮忙点个赞赞~~~