權限控制(vue)


權限控制(vue)

經常會遇到,角色權限控制問題,若是頁面控制,倒好說,可如果是當前頁面部分可見不可見,這就有些麻煩,如果加上條件就更加苛刻。之前只是簡單的v-if進行控制,如今想試試指令(網上一直有這些操作方式)

參考

參考了vue-element-admin -- 指令

應用場景

  • 權限控制
    • 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
        }
      

效果圖

  • 默認不顯示,數據回來顯示

    • 單個元素

    • 多個元素

  • 默認顯示,數據回來不顯示

    • 單個元素

    • 多個元素

總結

  • 雖然可以解決基本需求,但是還是有問題,若是兄弟元素都有權限控制,恐怕回顯時,會錯位
  • 因而推薦還是使用v-if
  • 上述方式,只能是應付簡單的,復雜的依舊有些吃力
  • 在指令執行時,提前拿到父節點和子節點的對應關系,然后在update時,進行全局獲取,因而生成的id必須唯一
  • 若是想使用,適用於其他場景,需要給需要權限控制的添加一個父元素,同時保證子元素唯一即可

知識點

  • cloneNode(true) 使用深度克隆是由於父元素因為實時變化才是用的,可以保留子節點
  • isEqualNode 用來判斷兩個子節點是否相同(長知識了)
  • update時,需要將節點添加到父節點上,此時 vnode, oldVnodeparent都沒有值


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM