通常沒(méi)有經(jīng)驗(yàn)的小伙伴們對(duì)頁(yè)面中一些按鈕或組件進(jìn)行權(quán)限控制會(huì)像以下這樣:
1.通常在vuex
的store
中存儲(chǔ)用戶的權(quán)限信息(一般是權(quán)限code數(shù)組捉撮,或者角色code數(shù)組)
export default {
name: '張三',
token: '',
permissions: ['DELETE_ARTICLE', 'USER_MANAGEMENT'],
}
2.在業(yè)務(wù)組件中使用mapState
獲取store
中的用戶權(quán)限信息屈留,再在模板通過(guò)v-if
判斷是否有目標(biāo)權(quán)限進(jìn)行條件顯示
<template>
<div>
<h2>這是一個(gè)文章列表頁(yè)面</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>
但是需要鑒權(quán)的業(yè)務(wù)組件非常多的時(shí)候祠够,就要在每個(gè)組件里都復(fù)制一份以上的重復(fù)代碼,下面針對(duì)以上現(xiàn)象我們封裝一個(gè)鑒權(quán)組件來(lái)改善這種情況:
1.第一步封裝一個(gè)名為Auth.vue
的組件,并刪除template
標(biāo)簽。
<script>
export default {
name: 'Auth'
}
</script>
2.第二步,添加render
函數(shù)乖阵,并在組件中使用mapState
獲取用戶權(quán)限信息,如果用戶有權(quán)限就返回默認(rèn)插槽预麸,如果沒(méi)有權(quán)限就返回null
<script>
import { mapState } from 'vuex'
export default {
name: 'Auth',
props: {
code: String, // 需要的權(quán)限
},
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.第三步就可以愉快的使用了瞪浸,將該組件注冊(cè)到全局并在業(yè)務(wù)組件中使用
在main.js
中:
import Auth from './components/Auth'
import Vue from 'vue'
Vue.component('sl-auth', Auth)
在業(yè)務(wù)組件中使用該組件:
<template>
<div>
<h2>這是一個(gè)文章列表頁(yè)面</h2>
<sl-auth code="DELETE_ARTICLE">
<el-button>刪除文章</el-button>
</sl-auth>
</div>
</template>
<script>
export default {
name: 'Demo',
}
</script>
代碼跟之前比精簡(jiǎn)了很多,針對(duì)以上vuex
用法還可以繼續(xù)優(yōu)化吏祸,可以將用戶權(quán)限Array
換成Map
的結(jié)構(gòu)并放在store
的getters
中对蒲,轉(zhuǎn)換操作一般只進(jìn)行一次,單次使用時(shí)間復(fù)雜度從O(n)降低到O(1)贡翘。
在store中:
export default new Vuex.Store({
modules: {
user
},
getters: {
// 用戶權(quán)限Map
getPermissionMap: state => {
const permissions = state.user.permissions
const permissionMap = new Map() // 創(chuàng)建一個(gè)空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, // 需要的權(quán)限
},
computed: {
...mapGetters(['getPermissionMap']), // 從getters里獲取權(quán)限Map
},
render() {
const { $slots, getPermissionMap, code } = this
return getPermissionMap.has(code) ? $slots.default : null // 通過(guò)Map.has()判斷是否擁有權(quán)限
}
}
</script>
現(xiàn)在鑒權(quán)組件就封裝好了蹈矮,查了一下資料,由于render
函數(shù)中不能使用template
標(biāo)簽做為根節(jié)點(diǎn)鸣驱,所以在使用該鑒權(quán)組件時(shí)包裹的子元素不能是多個(gè)泛鸟,錯(cuò)誤的使用方式:
<template>
<sl-auth code="DELETE_ARTICLE">
<el-button>刪除文章</el-button>
<el-button>刪除文章</el-button>
</sl-auth>
</template>
應(yīng)該多次使用該組件進(jìn)行包裹,正確的使用方式:
<template>
<sl-auth code="DELETE_ARTICLE">
<el-button>刪除文章</el-button>
</sl-auth>
<sl-auth code="DELETE_ARTICLE">
<el-button>刪除文章</el-button>
</sl-auth>
</template>
(完)