不管是在开发PC端或者H5端的时候,不管是面向B端还是C端的产品,都会面临权限控制的开发场景,此时不可能是一个一个的去写v-if或者v-show了。一般会根据当前用户从后端接口获取对应的权限码去控制页面、菜单、按钮的展示,在这里我们可以封装v-auth指令去实现多条件判断的按钮权限控制。最终实现的目标是:只需要一个简单的指令就能实现按钮权限的多条件判断,满足各种场景状态下的权限需求。如果对自定义指令还不是熟悉的童鞋,可以去官方复习一下再来看此文章:vue官方自定义指令

首先我们找到项目的入口文件main.js,在new Vue()之前添加相应的自定义权限指令代码就OK了。当然也可以把这些代码提取出来,导出,再main.js里面引入执行即可。其实两个方式代码都是一样的,只是写的方式不同而已,下面我们一一为大家讲解这这两个方式。

1
2
3
4
5
6
7
8
//在此添加自定义权限指令
//.....
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})

说明:v-auth传入的权限码可以是String或者Array,此外还提供跟数组some和every方法一样的修饰符。

第一种:直接写入main.js里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import Vue from 'vue'
import App from './App'
import store from './store'
import router from './router'
/**
* auth指令 v-auth="Array or String"
* 传入的权限码可以是数组或者是字符串
* 此外还有两个修饰符 some 和 every
* v-auth.some="Array" 表示满足其中一个资源即可(不设置修饰符情况下默认为some)
* v-auth.every= "Array" 表示列表的所资源必须存在
* 调用实例:
* <span v-auth.some="['admin1', 'admin2']"></span>
* <span v-auth.every="['admin1', 'admin2']"></span>
* <span v-auth="'admin1'"></span>
*/

// 删除节点dom
const remove = (el) => el.parentNode.removeChild(el)

Vue.directive('auth', {
inserted: (el, binding, vNode) => {
const { $root: vm } = vNode.context
// 获取当前用户拥有的权限列表(根据自身业务获取)
const access = vm.$store.getters.btnCode
console.log('access:', access)
// 获取传入的权限码value(string or array)和修饰符modifiers
// eslint-disable-next-line prefer-const
let { value, modifiers } = binding

// 判断条件:当传入的值不是数组或者字符串时,直接隐藏元素
if (!(typeof value === 'string' || value instanceof Array) || !value) {
remove(el)
return console.error('please set the value to a string or array.')
}

// 判断条件:如果传入的权限码是string则转化成数组
if (typeof value === 'string') {
value = [value]
}

/**
* 判断条件
* -修饰符为 every时 value数组只要有一个元素不存在access权限集内,隐藏元素
* -修饰符为 some或者没有时,value数组所有元素都不存在access权限集内,隐藏元素
*/
if ((modifiers.every && value.some(v => !access.includes(v))) || (!modifiers.every && value.every(v => !access.includes(v)))) {
remove(el)
}
}
})

new Vue({
el: '#app',
router,
store,
render: h => h(App)
})

第二种:提取到directives目录下的auth.js里面,再在main.js里面引用

auth.js代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* auth指令 v-auth="Array or String"
* 传入的权限码可以是数组或者是字符串
* 此外还有两个修饰符 some 和 every
* v-auth.some="Array" 表示满足其中一个资源即可(不设置修饰符情况下默认为some)
* v-auth.every= "Array" 表示列表的所资源必须存在
* 调用实例:
* <span v-auth.some="['admin1', 'admin2']"></span>
* <span v-auth.every="['admin1', 'admin2']"></span>
* <span v-auth="'admin1'"></span>
*/

// 删除节点dom
const remove = (el) => el.parentNode.removeChild(el)
function install(Vue, options = {}) {
Vue.directive(options.name || 'auth', {
inserted(el, binding, vNode) {
const { $root: vm } = vNode.context
// 获取当前用户拥有的权限列表(根据自身业务获取)
const access = vm.$store.getters.btnCode
console.log('access:', access)
// 获取传入的权限码value(string or array)和修饰符modifiers
// eslint-disable-next-line prefer-const
let { value, modifiers } = binding

// 判断条件:当传入的值不是数组或者字符串时,直接隐藏元素
if (!(typeof value === 'string' || value instanceof Array) || !value) {
remove(el)
return console.error('please set the value to a string or array.')
}

// 判断条件:如果传入的权限码是string则转化成数组
if (typeof value === 'string') {
value = [value]
}

/**
* 判断条件
* -修饰符为 every时 value数组只要有一个元素不存在access权限集内,隐藏元素
* -修饰符为 some或者没有时,value数组所有元素都不存在access权限集内,隐藏元素
*/
if ((modifiers.every && value.some(v => !access.includes(v))) || (!modifiers.every && value.every(v => !access.includes(v)))) {
remove(el)
}
}
})
}

export default { install }

main.js的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import Vue from 'vue'
import App from './App'
import store from './store'
import router from './router'

import auth from '@/directives/auth' // 在这里引入
Vue.use(auth)

new Vue({
el: '#app',
router,
store,
render: h => h(App)
})