Vue3.3.5版本自定义指令拦截click事件(包含3.3.4及以下的方案)

580 阅读1分钟

当我使用v-permission的指令时,如果当前登录的角色不是ADMIN,那么应用应该要阻止点击的后续事件。

1. 自定义组件

<script setup>
const emits = defineEmits({
  action: (payload) => payload.length > 0
})

function deleted() {
  console.log("删除!")
  emits('action', 'delete')
}
</script>

<template>
  <button @click="deleted">阻止点击事件</button>
</template>

2. 使用

<script>
function click(payload) {
  console.log("删除!", payload)
}
</script>

<template>
    <CustomButton v-permissions="['ADMIN']" @action="click"></CustomButton>
</template>

3. 实现(Vue3.3.5)

// main.js
app.directive('permissions', {
  mounted(el, binding, vNode) {
    const {getRole} = useRoleStore()
    if (!Array.isArray(binding.value)) console.error('permission must be array')
    if (!binding.value.includes(getRole)) return
    const vei_key = Object.getOwnPropertySymbols(el)?.[0]
    if (el[vei_key].onClick) {
      el[vei_key].onClick.value = () => console.error('Administrator privileges are required')
    }
  }
})

3.3.5后vue对操作内部属性的方式进行了修复

具体的Github Issues在这里

Custom Directives do not correctly obtain Vue Event Invoker · Issue #9571 · vuejs/core (github.com)

4. 下面的为3.3.4以及以下的实现方式

// main.js
app.directive('permissions', {
  mounted(el, binding, vNode) {
    const {getRole} = useRoleStore()
    if (!Array.isArray(binding.value)) console.error('permission must be array')
    if (!binding.value.includes(getRole)) return
    if (el._vei.onClick) {
      el._vei.onClick.value = () => console.error('Administrator privileges are required')
    }
  }
})

实际上就是3.3.5将获取私有属性的_vei给包在了Symbol里

想要获取需要使用到Object.getOwnPropertySymbols(el)?.[0]

用这种方式去拦截click的好处是我在使用自定义组件的同时依然可以使用@click事件,当该组件确实需要细粒度的控制权限时,我可以用v-permissions这种方式对组件进行扩展,而不是删除@click(如果不理解这句话,可以参考最下面的参考文章)

! 如果不仅仅是要对click进行拦截还需要可能 隐藏|换色|不可点击,那么需要再v-permissions后面再增加参数即可。

例如:v-permissions:disabled|hidden|color ... 等等。

具体可以看官网的参数和修饰符:

自定义指令 | Vue.js (vuejs.org)


参考:Vue3中用自定义指令拦截点击事件,点击事件添加权限 - 掘金 (juejin.cn)

感谢:Aaminly 的个人主页 - 动态 - 掘金 (juejin.cn)