利用 Vue 自定义指令实现按钮级别权限控制

最近公司的老项目进行重构,前端技术栈也从原来的 AngularJS 转到 Vue,在架构到页面按钮级别的权限这一块时,我打算利用 vue 的自定义指令来实现。今天就来记录一下实现方式,话不多说,直接上代码。

v-permission 自定义指令

Vue 自定义指令有全局注册和局部注册两种方式,考虑到项目中全局都要用到,所以我们这里采用的是全局注册的方式。

  • src 目录下新建 directives 文件夹,并创建permission.js以及index.js

    // permission.js
    import Store from '../store/index.js'
    
    const checkPermission = (productProviderName, productName, action) => {
      const permissionObj = Store.getters.permissions
      if (!permissionObj[productProviderName]) return false
      const permissions = permissionObj[productProviderName][productName]
      if (!permissions) return false
      return permissions.indexOf(action) > -1
    }
    
    function fn (el, binding) {
      let permission = binding.value // 获取到 v-permission 所绑定的值
      if (typeof permission === 'string') {
        if (permission) {
          const arr = permission.split('.')
          if (arr.length === 3) {
            let hasPermission = checkPermission(arr[0], arr[1], arr[2])
            if (!hasPermission) {
              // 没有权限则移除 dom 元素
              el.parentNode && el.parentNode.removeChild(el)
            } else {
              // 有权限则追加之前缓存的 dom 元素
              el.cacheParentElement && el.cacheParentElement.appendChild(el.cacheElement)
            }
          } else {
            console.error(`The value bound to v-permission should be like v-permission="'aliyun.ecs.PURCHASE'".`)
          }
        } else {
          console.error('The value bound to v-permission cannot be empty.')
        }
      } else {
        console.error('The value type bound to v-permission should be String.')
      }
    }
    
    const permission = {
      inserted: function (el, binding) {
        // !!!敲重点
        el.cacheElement = el // 缓存本节点
        el.cacheParentElement = el.parentNode // 缓存父节点
        fn(el, binding)
      },
      update: function (el, binding) {
        fn(el, binding)
      }
    }
    
    export default permission
    
    // index.js
    import permission from './permission'
    
    const directives = {
      permission
    }
    
    export default {
      install(Vue) {
        // 批量注册自定义指令
        Object.keys(directives).forEach((key) => {
          Vue.directive(key, directives[key])
        })
      }
    }
    
  • main.js 中引入并调用

    import Vue from 'vue'
    import directives from './directives/index.js'
    Vue.use(directives) // 以插件的方式引入
    
  • 在组件中的使用方式

    <template>
      <button v-permission="'aliyun.ecs.PURCHASE'">Create Instance</el-button>
    </template>
    

Vue 自定义指令相关拓展

钩子函数

一个指令定义对象可以提供如下几个钩子函数 (均为可选):

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。

  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

  • unbind:只调用一次,指令与元素解绑时调用。

钩子函数参数

指令钩子函数会被传入以下参数:

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象,包含以下 property:
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
    • oldValue:指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
  • vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
  • oldVnode:上一个虚拟节点,仅在 updatecomponentUpdated 钩子中可用。

想要了解更多,请移步官方文档

Vue 插件相关拓展

使用插件

通过全局方法 Vue.use() 使用插件。它需要在你调用 new Vue()启动应用之前完成。

// 调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin, options)

new Vue({
  // ...组件选项
})

开发插件

Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象。

const MyPlugin = {
  install(Vue, options) {
    // do something
  }
}
export default MyPlugin

想要了解更多,请移步官方文档

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值