我们知道常规后台管理项目都需要设置路由权限用于针对不同的用户展示不同的路由,也可以理解以此来展示和操作不同的菜单栏。然后关于vue-element-admin的路由权限官方也有说明,我这里是单独针对官方的说明的基础上,做进一步的个人做法案列,
官网地址: 介绍 | vue-element-admin
一、大体步骤
1、配置动态路由,在src/router/index.js里面配置动态路由asyncRoutes
2、在登录页面(view/login/index.vue)进行登录,将关键值存放在store和缓存之中
3、在permission.js里面做了一个全局路由守卫,这里将提交调用store里面的方法,同时将
获取的路由追加到项目的路由之中
4、在store里面执行了过滤路由的操作,只保留对应的路由
5、在layout/components/sidebar/index.vue 这里也就我们配置侧边栏的地方,获取store存储的对应过滤的路由权限,将之渲染的页面之中
二、具体操作
1、设置动态路由
src/router/index.js 设置动态路由,静态路由这里不再展示,只需要不需要用权限控制的路由放进constantRoutes就行。注意这里tab是很关键的一点,我们通过这个唯一标识去做过滤,拿到对应的路由权限
export const asyncRoutes = [
{
path: "/gamerecord",
component: Layout,
redirect: "/gamerecord/globalrecords",
name: "gamerecord",
tab: 103,
meta: {
title: "游戏记录",
icon: "el-icon-s-order",
noCache: true,
},
children: [
{
path: "globalrecords",
component: () => import("@/views/gamerecord/globalrecords"),
name: "Globalrecords",
tab: 103201,
meta: { title: "所有记录", noCache: true },
}
],
},
]
2、登录操作
view/login/index.vue 登录页面
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.$store.dispatch('user/login', this.loginForm)
.then(() => {
// this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
this.$router.push({ path: '/', query: this.otherQuery })
this.loading = false
})
.catch(() => {
this.loading = false
})
} else {
return false
}
})
},
这里进行了用户操作,同时将值在store里面进行的提交
store/modules/user.js
login({ commit }, userInfo) {
const { username, password, yzm } = userInfo;
return new Promise((resolve, reject) => {
login({ account: username.trim(), accountPwd: password, code: yzm })
.then((res) => {
if (res.code == 0 && res.data) {
const { data } = res;
commit("SET_TOKEN", data);
setToken(data);
Message({ type: "success", message: "登录成功!", showClose: true,
});
} else {
Message({ type: "error", message: res.message, showClose: true });
}
resolve();
})
.catch((error) => {
reject(error);
});
});
},
这里我们将登录传递过来的参数用于请求接口请求,并且将登录之后的参数存在缓存和store状态管理之中
例我的返回值如下,只展示部分,permisssionId这里就是此用户所用的权限,account就是用户登录的账户角色
3、全局路由守卫
在src/permission.js里面,这里官方是做了一个路由全局守卫,我们需要再这里修改一些东西,具体操作如下
因为下载的版本的是英文版的,所以这里是一些原有注释,这里并没有修改
我们需要获取用户的角色代号,其次需要获取用户的所拥有的路由权限,同时,我们还需要注意一点,就是 404
页面一定要最后加载,如果放在constantRoutes一同声明了404
,后面的所以页面都会被拦截到404
router.beforeEach(async (to, from, next) => {
// start progress bar
NProgress.start();
// set page title
document.title = getPageTitle(to.meta.title);
// determine whether the user has logged in
const hasToken = getToken();
if (hasToken) {
if (to.path === "/login") {
// if is logged in, redirect to the home page
next({ path: "/" });
NProgress.done(); // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
} else {
// determine whether the user has obtained his permission roles through getInfo
const hasRoles = store.getters.roles && store.getters.roles.length > 0;
if (hasRoles) {
next();
} else {
try {
// get user info
// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
const { roles } = await store.dispatch("user/getInfo");
let accessRoutes = await store.dispatch( "permission/generateRoutes", roles );
let newaccessRoutes = accessRoutes.concat([ { path: "*", redirect: "/404", hidden: true },]);
router.addRoutes(newaccessRoutes);
next({ ...to, replace: true });
} catch (error) {
await store.dispatch("user/resetToken");
Message.error(error || "Has Error");
next(`/login?redirect=${to.path}`);
NProgress.done();
}
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next();
} else {
// other pages that do not have permission to access are redirected to the login page.
next(`/login?redirect=${to.path}`);
NProgress.done();
}
}
});
4、路由过滤
这里我们回到 store/modules/user.js
· 我是将登录后返回的账号角色,比如此时就为 admin 或者 edior都可以,但是注意我在这里admin就代表超级管理员拥有所有权限。这里的剩余的其它参数如avatar用户头像等,因为没有单独要求,所以这里直接赋值。
getInfo({ commit, state }) {
return new Promise((resolve, reject) => {
let role = JSON.parse(getToken()).account;
const data = {
roles: [role],
introduction: "I am a super administrator",
avatar:"https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif",
name: "Rfalcon",
};
if (!data) {
reject("验证失败,请重新登录!");
}
const { roles, name, avatar, introduction } = data;
commit("SET_ROLES", roles);
commit("SET_NAME", name);
commit("SET_AVATAR", avatar);
commit("SET_INTRODUCTION", introduction);
resolve(data);
}).catch((error) => {
reject(error);
});
// })
},
另一边我们还需要拿到角色所对应的路由 在store/modules/permission.js
如果是超级管理员,我们就直接使用我们在router.js声明的动态路由asyncRoutes,如果不是那我们就需要单独操作过滤路由,通过我们存储的用户对拥有的权限和我们router.js里面存储的所有权限进行对比,过滤出最终的路由权限,然后在src/permission.js里面的全局路由守卫中拼接404路由,最后使用router.addRoutes()追加进去。这里在store/modules/permission.js同时还将过滤后的拼接固定路由,并提交存储到store的routes里
function hasPermission(permissionIds, route) {
if (route.meta && route.meta.roles) {
return roles.some(role => route.meta.roles.includes(role))
} else {
return true
}
}
/**
* Filter asynchronous routing tables by recursion
* @param routes asyncRoutes
* @param roles
*/
export function filterAsyncRoutes(routes, roles) {
const res = []
let data=JSON.parse(getToken()).permissionId
if(data.indexOf(',')>-1){
data=data.split(',')
}else{
data=[data]
}
routes.forEach(route => {
const tmp = { ...route }
if (hasPermission(roles, tmp)) {
if(data.indexOf(String(tmp.tab)) > -1){
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
res.push(tmp)
}
}
})
return res
}
generateRoutes({ commit }, roles) {
return new Promise(resolve => {
let accessedRoutes
if (roles.includes('admin')) {
accessedRoutes = asyncRoutes || []
} else {
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
}
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
}
5、侧边栏的渲染
这里我们拿到store里面存储的状态值,也就是我们在上一步存储的routes,然后渲染页面,这里就完成了动态路由和菜单栏的渲染了
三、总结
最终实现的步骤也如上所示,我们只需要再对应的设置相应的方法,再结合自己项目的实际情况做处理就行,关键点就是存储用户登录后的权限和过滤路由,侧边栏的展示官方是根据你存储在store里面的路由渲染的,所以这里并不需要再做其他操作。
以上是对vue-element-admin的动态路由个人操作示例,不足之处恳请各位大佬批评指正,谢谢!!!