通常没有经验的小伙伴们对页面中一些按钮或组件进行权限控制会像以下这样:
1.通常在vuex
的store
中存储用户的权限信息(一般是权限code数组,或者角色code数组)
export default {
name: '张三',
token: '',
permissions: ['DELETE_ARTICLE', 'USER_MANAGEMENT'],
}
2.在业务组件中使用mapState
获取store
中的用户权限信息,再在模板通过v-if
判断是否有目标权限进行条件显示
<template>
<div>
<h2>这是一个文章列表页面</h2>
<el-button v-if="showDeleteButton">删除文章</el-button>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'Demo',
computed: {
...mapState({
permissions: state => state.user.permissions
}),
showDeleteButton() {
return this.permissions.some(code => code === 'DELETE_ARTICLE')
}
},
}
</script>
但是需要鉴权的业务组件非常多的时候,就要在每个组件里都复制一份以上的重复代码,下面针对以上现象我们封装一个鉴权组件来改善这种情况:
1.第一步封装一个名为Auth.vue
的组件,并删除template
标签。
<script>
export default {
name: 'Auth'
}
</script>
2.第二步,添加render
函数,并在组件中使用mapState
获取用户权限信息,如果用户有权限就返回默认插槽,如果没有权限就返回null
<script>
import { mapState } from 'vuex'
export default {
name: 'Auth',
props: {
code: String, // 需要的权限
},
computed: {
...mapState({
permissions: state => state.user.permissions
})
},
render() {
const { $slots, permissions, code } = this
const hasPermission = permissions.some(p => p === code)
return hasPermission ? $slots.default : null
}
}
</script>
3.第三步就可以愉快的使用了,将该组件注册到全局并在业务组件中使用
在main.js
中:
import Auth from './components/Auth'
import Vue from 'vue'
Vue.component('sl-auth', Auth)
在业务组件中使用该组件:
<template>
<div>
<h2>这是一个文章列表页面</h2>
<sl-auth code="DELETE_ARTICLE">
<el-button>删除文章</el-button>
</sl-auth>
</div>
</template>
<script>
export default {
name: 'Demo',
}
</script>
代码跟之前比精简了很多,针对以上vuex
用法还可以继续优化,可以将用户权限Array
换成Map
的结构并放在store
的getters
中,转换操作一般只进行一次,单次使用时间复杂度从O(n)降低到O(1)。
在store中:
export default new Vuex.Store({
modules: {
user
},
getters: {
// 用户权限Map
getPermissionMap: state => {
const permissions = state.user.permissions
const permissionMap = new Map() // 创建一个空Map
permissions.forEach(code => permissionMap.set(code, code))
return permissionMap
},
}
})
然后改造Auth.vue
:
<script>
import { mapGetters } from 'vuex' // 这里换成mapGetters
export default {
name: 'Auth',
props: {
code: String, // 需要的权限
},
computed: {
...mapGetters(['getPermissionMap']), // 从getters里获取权限Map
},
render() {
const { $slots, getPermissionMap, code } = this
return getPermissionMap.has(code) ? $slots.default : null // 通过Map.has()判断是否拥有权限
}
}
</script>
现在鉴权组件就封装好了,查了一下资料,由于render
函数中不能使用template
标签做为根节点,所以在使用该鉴权组件时包裹的子元素不能是多个,错误的使用方式:
<template>
<sl-auth code="DELETE_ARTICLE">
<el-button>删除文章</el-button>
<el-button>删除文章</el-button>
</sl-auth>
</template>
应该多次使用该组件进行包裹,正确的使用方式:
<template>
<sl-auth code="DELETE_ARTICLE">
<el-button>删除文章</el-button>
</sl-auth>
<sl-auth code="DELETE_ARTICLE">
<el-button>删除文章</el-button>
</sl-auth>
</template>
(完)
网友评论