最近负责的项目中有一个需求是这样的:
管理员可以给其他用户设置某些按钮的权限,比如编辑,新增等按钮的权限,当被设置为无权限时,那么点击编辑或新增的时候,是无法进入编辑或新增页面的,而是通过提示框来提示用户无权限。
这里有个地方需要注意,虽然不能通过点击编辑或新增来进入相应的页面,但是却可以通过路由来访问编辑或者新增页面,这不是我们想看到的,如果可以通过路由直接访问页面,那按钮的权限控制就相当于形同虚设,没有任何意义了。
因此这里采用了导航守卫,来限制用户是否有权限访问某些页面。
实际上,对于每个按钮是否有权限可以去进行点击操作,是根据后端返回的接口数据来决定的。数据格式类似于下面这种格式
{
code: 0,
data: [{
comment: '编辑',
checkStatus: false
}, {
comment: '新增',
checkStatus: true
}]
}
这里的code可以当做状态码来看待,当code为0,说明请求成功了,而data则是通过接口获取到的按钮的权限, comment是按钮名称,checkStatus是按钮的状态,在开头我已经说明了,管理员可以给不同的用户设置按钮的权限,所以假设我给小明新增编辑按钮的权限,那么checkStatus就是为true,反之为false
那么我们怎么通过这个数据来判断用户是否有权限访问对应的页面呢。当然是一开始提到的导航守卫,我用的是路由独享守卫,也就是写在路由配置里的导航守卫,格式类似于下面的形式
routes: [{
name: 'article-edit'
path: '/article/edit',
beforeEnter: (to, from, next) {
}
}]
那么第一步,当我们进入某个页面的时候,这个页面会有一些可以被分配权限的按钮,所以我们首先要通过接口获取这个页面的按钮权限列表,也就是我上面贴的第一段代码。我想说明的一点发送请求的那部分代码因人而异
routes: [{
name: 'article-edit',
path: '/article/edit',
beforeEnter: (to, from, next) {
http.get(apis.getButtonsPowerList, {
params: {
pageId: xxxx
}
}).then(res => {
if(res.code === 0) { // code为0说明请求成功
let btnsPowerList = res.data // 获取按钮权限列表
for(let i = 0; i < btnsPowerList.length; i++) {
if(btnsPowerList[i].comment === '编辑') { // 找到comment为编辑的按钮
if(btnsPowerList[i].checkStatus) { // 判断编辑按钮的checkStatus是否为true
next() // 如果为true,表示有权限,则进入相应页面
} else { // 否则提示用户没有访问权限,并且退回上一页面
setTimeout(() => {
window.history.go(-1)
})
alert('您没有访问该页面的权限')
}
}
}
}
})
}
}]
这样写其实很乱,并且不具备复用性,如果有很多个按钮需要增加权限控制,意味着我们要写很多遍同样的代码,这样是非常不好的。因此我们来封装一下代码。
export function isAuthRoute(comment, pageId, next) {
new Promise(resolve => {
_isAuth(comment, pageId, resolve)
}).then(res => {
if(!res) {
setTimeout(() => {
window.history.go(-1)
}, 1500)
alert('您没有访问该页面的权限')
} else {
next()
}
})
}
function _isAuth(comment, pageId, callback) {
http.get(apis.getButtonsPowerList, {
params: {
pageId
}
}).then(res => {
if(res.code === 0) {
let btnsPowerList = res.data
for(let i = 0; i < btnsPowerList.length; i++) {
if(btnsPowerList[i].comment === comment) {
if(btnsPowerList[i].checkStatus) {
callback(true)
} else {
callback(false)
}
}
}
}
})
}
之后,我们只需要在需要用到权限控制的路由加上
routes: [{
name: 'article-edit',
path: '/article/edit',
beforeEnter: (to, from, next) {
isAuthRoute('编辑', pageId, next)
}
}]
可以看到,封装后的代码简洁了很多,我们只需要根据不同的按钮,来传不同的按钮名称以及这个按钮所在的页面的pageId即可。
但其实我认为重点并不在这个权限控制上面,而是整个代码的运行过程。在倒数第二张代码里面,可以看到有同时使用了promise和http请求,实际上他们都是异步的,我们需要在获取到数据之后才可以继续往下走,也就是说虽然他们都是异步的,但必须按照顺序执行。
Promise中,then中的回调函数是必须等待promise中的resolve被执行之后才会被执行,但前提是数据已经获取到了,否则promise里的then的回调将会获取到一个undefined的值,这样的话代码就有问题了。
为了解决这个问题,我们就必须把resolve当做一个回调函数,当数据获取完之后,将数据放到resolve中,传给promise中的then里面的回调函数,这样才能够确保代码的一个顺序性。
因此可以看到,在代码中,我将resolve作为参数,传给了_isAuth这个函数,当_isAuth发送请求并且获取到数据之后,才调用resolve,调用callback就是调用了resolve。之后才轮到promise的回调函数来执行代码。
最后,虽然不是很难的东西,甚至还挺简单的,但我认为这样的做法挺好的,起码学习了如何封装代码确保可复用性,以及如何在让多个异步之间进行一个有序的执行,所以今天将所学的知识记录在这里。希望能够帮到大家,谢谢。