權限控制(vue)
經常會遇到,角色權限控制問題,若是頁面控制,倒好說,可如果是當前頁面部分可見不可見,這就有些麻煩,如果加上條件就更加苛刻。之前只是簡單的v-if進行控制,如今想試試指令(網上一直有這些操作方式)
參考
應用場景
- 權限控制
- dom隱藏(不推薦)
- 直接從dom節點刪除
- 依據傳入的數據動態進行修改
代碼
需求:需要實現一個依據動態參數進行修改的模塊
-
test.vue
template
<div class="test-height"> <!-- 指令調用,status是動態參數 --> <h1 v-permission="{ role: ['so'], status }">test</h1> </div>js
import permission from '@/directives/permission' export default { ... directives: { permission }, data () { return { status: false } }, mounted () { // 動態修改參數 setTimeout(() => { this.status = !this.status }, 1000) } } -
permission.js
import store from '@/store' const permission = (el, binding, vnode, oldVnode) => { const { value, oldValue } = binding if (!value || (value.role && !Array.isArray(value.role))) { throw new Error(`need roles! Like v-permission="{ role: ['admin','editor'], [status 可傳 boolean]}"`) } // 綁定的參數 const status = value.hasOwnProperty('status') ? value.status : false const roles = store.getters && store.getters.roles const permissionRoles = value.role || [] const hasPermission = roles.some(role => { return permissionRoles.includes(role) }) if (!hasPermission || (hasPermission && status)) { /** * TODO: * 1. 給父元素添加唯一id * 2. 同時找到子元素當前父元素的第幾個位置 */ const rid = getRandomId() const index = getChildInParentPosition(el) el.parentNode.setAttribute('id', rid) el.dataset.id = rid el.dataset.index = index el.parentNode && el.parentNode.removeChild(el) } // 判斷條件 if (oldValue && oldValue && oldValue.status === true && value.status === false) { // 此處會在 update時觸發 const { index, id } = el.dataset const parent = document.getElementById(id) // 根據index找到需要插入父節點的位置 parent.insertBefore(el, Array.from(parent.children)[index]) } } export default { // 此處父元素存在 inserted: permission, // 此處數據更新 update: permission }- 隨機生成id
function getRandomId () { var randomId = 'yxyxyxxyxyy'.replace(/[xy]/g, function (item) { var n = Math.random() * 12 | 0 var v = item === 'x' ? n : (n & 0x3 | 0x8) v = item === 'y' ? 'abcdefghijklmnopqrstuvwsyz'.substr(Math.random() * 26 | 0, 1) : v return v.toString(16) }) return randomId } - 找到子節點在父節點中的位置
function getChildInParentPosition (node) { // 用來保留子元素 【cloneNode(true) 深度克隆】 const Parent = node.parentNode.cloneNode(true) let key = -1 Array.from(Parent.children).filter((item, index) => { // 判斷子節點是否相同 【isEqualNode】 if (item.isEqualNode(node)) { key = index } }) return key }
- 隨機生成id
效果圖
-
默認不顯示,數據回來顯示
- 單個元素

-
多個元素

-
默認顯示,數據回來不顯示
-
單個元素

-
多個元素

-
總結
- 雖然可以解決基本需求,但是還是有問題,若是兄弟元素都有權限控制,恐怕回顯時,會錯位
- 因而推薦還是使用
v-if - 上述方式,只能是應付簡單的,復雜的依舊有些吃力
- 在指令執行時,提前拿到父節點和子節點的對應關系,然后在
update時,進行全局獲取,因而生成的id必須唯一 - 若是想使用,適用於其他場景,需要給需要權限控制的添加一個父元素,同時保證子元素唯一即可
知識點
cloneNode(true)使用深度克隆是由於父元素因為實時變化才是用的,可以保留子節點isEqualNode用來判斷兩個子節點是否相同(長知識了)update時,需要將節點添加到父節點上,此時vnode, oldVnode的parent都沒有值
