-
在前端项目当中,尤其是一些后台管理系统会涉及到路由的权限问题。不同的用户所能访问的菜单是不一样的,也有一些不一样的操作,今天的话喝大家分享一下关于在vue2项目中路由的权限。
-
一般情况我们前端会在roter里面定义一个静态路由,这个路由是任何登录过的用户都能访问的路由,比如说home、login
router文件夹下面的index.js
js
import Router from 'vue-router'
import vue from "vue"
// 静态路由 也就是只要你登录了 不管你是什么权限 都能够访问的路由
const constantRoutes=[
{
name:'home',
path:'/home',
component:()=>import('@/views/home')
},
{
name:'login',
path:'/login',
component:()=>import('@/views/login')
},
]
export default new Router({
mode: "history", // 去掉url中的#
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
/// 在main.js 中去引入并且使用
import router from "./router";
new Vue({
el: "#app",
router,
store,
render: (h) => h(App),
});
- 然后就可以访问这两个路由了, 权限一般是后端处理,我们前端需要把当前用户登录的id或者是其他的标识,通过一个接口发送给后端,然后后端会给我们返回一个路由表类似于一个数组。类似于这样,id代表当前路由的id, pid为对应的上级路由id,(就是他爸爸的id)若pid为0则当前路由为一级路由(没有爸爸),很明显学生添加的id为2 pid为1,所以学生添加是学生管理的子路由, 学生管理的pid为0 所以学生管理为一级路由。
js
[
{
"id": 1, // 代表我们路由id
"pid": "0",// 上级id 0 代表一级路由
"name": "student",
"path": "/student",
"title": "学生管理"
},
{
"id": 2,
"pid": "1",
"name": "studentAdd",
"path": "/student/studentAdd",
"title": "学生添加"
},
{
"id": 3,
"pid": "2",
"name": "studentDetail",
"path": "/student/studentDetail",
"title": "学生详情"
},
{
"id": 4,
"pid": "1",
"name": "studentDelete",
"path": "/student/studentDelete",
"title": "学生删除"
},
{
"id": 5,
"pid": "0",
"name": "teacher",
"path": "/teacher",
"title": "教师管理"
},
{
"id": 6,
"pid": "5",
"name": "teacherAdd",
"path": "/teacher/teacherAdd",
"title": "教师新增"
},
{
"id": 6,
"pid": "5",
"name": "teacherDelete",
"path": "/teacher/teacherDelete",
"title": "教师删除"
}
]
- 我们前端拿到这样的数据之后会进行数据格式的处理, 渲染成路由树。下面我们在util文件夹下的index.js中定义一个transformTree函数
js
// 转为树结构
function transformTree(routes) {
// 根据id 首先区分一级路由和子路由
const parents = routes.filter(p => p.pid == 0)
const children = routes.filter(p => p.pid != 0)
calcRouteTree(parents, children)
// 处理
function calcRouteTree(parents, children) {
parents.map(p => {
children.map((c, i) => {
if (c.pid == p.id) { // 代表c路由是p的儿子路由
//深拷贝防止数据污染
let _c = JSON.parse(JSON.stringify(children))
_c.splice(i, 1) // 排他操作
// 把当前子路由作为parent 其他的子路由作为children
calcRouteTree([c], _c)
// 这一步得好好的理解 一开始接触的话可能有点绕 自己拿一个简单的例子好好体会
if (p.children) {
p.children.push(c)
} else {
p.children = [c]
}
}
})
})
}
return parents
}
- 经过上面的处理我们可以得到类似与这样的数据,变成我们熟知的数据格式了
js
[
{
"id": 1, // 代表我们路由id
"pid": "0",// 上级id 0 代表一级路由
"name": "student",
"path": "/student",
"title": "学生管理",
children: [
{
"id": 2,
"pid": "1",
"name": "studentAdd",
"path": "/student/studentAdd",
"title": "学生添加",
children: [
{
"id": 3,
"pid": "2",
"name": "studentDetail",
"path": "/student/studentDetail",
"title": "学生详情"
}
]
},
{
"id": 4,
"pid": "1",
"name": "studentDelete",
"path": "/student/studentDelete",
"title": "学生删除"
},
]
}
]
- 上面一步是转为树结构,当然还不是我们真正需要的路由,我们还需要另外一个calcTureRoute函数帮我们处理。这个函数是将我们的树结构真正的转化为路由表, 说白了就是加一个component属性,以后可以用router.addRoutes(routes) 添加到我们的路由当中
js
function calcTureRoute(routes) {
const result = routes.map(item => {
const data = {
name: item.name,
path: item.path,
component:()=>import(`@/views/${item.name}`)
}
if (item.children) {
data.children = calcTureRoute(item.children)
}
return data
})
return result
}
- 我们什么时候动态添加路由呢?下面我们来做一下路由守卫, 新建一个premiss.js文件夹,在main.js当中引入,引入代表把这个稳健执行一次。 我们把用户的信息都存储在vuex中,
js
# vuex 仓库
import {transformRouteTree,calcTureRoute } from '@/utils/index.js' // 上面讲到的两个函数
const state
state={
userInfo:{},
routerTree:[]
}
}
const mutations={
setUserInfo(state,userInfo){
state.userInfo=userInfo
},
setRouterTree(state,tree){
state.routerTree=tree
},
},
const actions={
async getUserInfo({commit,state}){
// 1. 获取用户数据
const userInfo={name:"张三",token:"123456",role:"admin"}// 这里的数据是我写假数据,应该是要用接口拿
commit('setUserInfo',userInfo) //数据拿完之后存储用户信息到user仓库
setToken('token',userInfo.token) // 存入token到cooke中
//2. 接下来获取权限路由数据 将来用接口拿的
const paylod=[数据] // 后端接口数据 这里的数据是第三部分的数据 上面已经讲到了
//3. 渲染树结构
const result= transformRouteTree(paylod)
commit('setRouterTree',result) //存储到user仓库中
}
Premissioin.js 文件
import router from "vue-router"
import store from './store' // 引入仓库
import {getToken,setToken}
router.beforeEach((to,from ,next)=>{
// 已经登录
if (getToken()) { // 登录成功时候获取用户信息的时候 就存入到了cookie当中
if (to.path = "/login") {
next({ path: '/' }) //已经登录 不能在跳转到登录
} else {
if (!store.state.user.info) {
// 这里防止页面刷新 vuex丢失数据 重新获取一遍用户
的信息
//数据没了重新获取一遍数据
await store.dispatch('getUserInfo') // 为什么要await一下呢 就是为了后端路由数据拿回来 前端处理完毕之后
// 现在user仓库中已经有了 routerTree结构 接下来我们渲染成真正的路由
const routes = calcTureRoute(store.state.user.routerTree结构)
router.addRouters(routes) // 加入动态路由
} else {
next() //已经登录了 没有刷新页面 正常放行
}
}
} else {
// 如果没有登录 先看看你走的是不是白名单,就是说你不用登录就可以访问的路由,一般的话有注册、首页等等
const whiteList = ['/home', '/register'] // 举两个例子
if (whiteList.includes(to.path)) {
// 如果用户没有登录 去到的是白名单当中的路由就放行
next()
} else {
//否则你既没有登录 也不是去的白名单路由 就跳转到登录
next({ path: '/login' })
}
}
)
}
注意点:
- 唯一难以理解的就是上面给出的递归函数,这个得好好的琢磨。
- 页面刷新的时候,会导致仓库的数据清空,有token情况下用户数据没了,在仓库中再次请求一次用户数据就行了。
- 每次路由跳转都会执行beforeEach函数, 把你小子拦截下来 自己盘问一番。就是这个意思
- 根据user仓库中的routerTree去渲染Menu菜单列表,这个作者就不赘述了。
路由鉴权大致的思想就是这样,上面给出了部分代码,一定要结合到实际项目当中去。本文出自作者本人实际经验。若有错误多多指正! 感谢支持。