通常,大家都是在指令中绑定事件,而我遇到一种场景是希望阻止事件触发,准确地讲,是阻止元素或组件绑定的事件 handler 的执行。

这个场景是基于权限控制诞生的,网上能查到资料,不少的实践中,都使用自定义指令控制按钮级别的权限控制。而这些实践中,多数都是控制按钮的显隐,这点不难实现。但实际中,可能也会有点击按钮,然后通过提示告知用户无权限操作的需求。因此我希望权限指令 v-permission 也能适应这种场景。

实现的思路其实也很简单,即先移除原有事件监听,再添加新的监听。问题就在于第一步比较难实现。

经过一番研究,最后我将这个问题分为两种情况:

  • vue 自定义事件
  • 原生事件

vue 自定义事件是可以禁用的,但是原生事件比较麻烦,想要移除原生事件的监听,需要提供原有绑定的函数,而这个信息无法在指令的 hook 中获取到(本来寄希望于 vnode, 然而多次尝试后无果)。所以最终是没有完全实现我想要的功能,只实现了一个半血版。demo 如下:

import { on } from 'element-ui/src/utils/dom'
import { Message } from 'element-ui'

Vue.directive('permission', {
  inserted: (el, binding, vnode) => {
      // 禁用 click 兼容性检测
      if (!vnode.componentInstance) {
        alert("v-permission 不支持用在普通dom元素")
        return
      }
      if (vnode.data.nativeOn && vnode.data.nativeOn.click) {
        alert("v-permission 不支持 click.native")
        return
      }

      // 禁用点击事件(组件)
      if (vnode.componentInstance) {
        vnode.componentInstance.$off('click')
      }

      on(el, 'click', function (e) {
        e.preventDefault()
        e.stopPropagation()
        Message.error("您无权进行此操作")
      })
  }
})

使用示例:

// 支持
<el-button v-permission @click="handleClick()"></el-button>

// 不支持,因为使用了 .native 修饰符,无法移除原有事件监听,即无法阻止 handleClick 的执行
<el-button v-permission @click.native="handleClick()"></el-button>

// 不支持,因为是元素dom,无法移除原有事件监听,即无法阻止 handleClick 的执行
<button v-permission @click="handleClick()"></button>

若朋友想到其他的实现思路,欢迎赐教。