自定义指令(详细完整版)

0 阅读2分钟

一、自定义指令的生命周期钩子

钩子函数促发时机常用参数
created绑定元素属性/事件监听器应用前触发el, binding, vnode
beforeMount元素被挂载到DOM前触发el, binding, vnode
mounted元素被挂载到DOM后触发el, binding, vnode
beforeUpdate组件更新前触发el, binding, vnode, prevVnode
updated组件更新后触发el, binding, vnode, prevVnode
beforeUnmount元素从DOM中卸载前触发el, binding, vnode
unmounted元素从DOM中卸载后触发el, binding, vnode

二、钩子参数

el : 指令绑定的真实DOM

binding : 一个对象,包含以下属性

value : 传递给指令的值
oldValue : 之前的值,仅在 beforeUpdate  updated 中可用
arg : 传递给指令的参数,例如:v-directive:test中,参数为test
modifiers : 一个包含修饰符的对象,例如:v-directive.foo.bar,那么修饰符对象为{foo:true,bar:true}
instance : 使用指令的当前组件实例

vnode : 绑定元素的底层VNode

prevVnode : 之前渲染中指令绑定的元素VNode,仅在 beforeUpdate 和 updated 中可用

三、局部自定义指令

例如:让input输入框聚焦

<template>
  <div>
    <input v-focus="true" />
  </div>
</template>

<script setup lang="ts">
const vFocus = {
  mounted(el, binding) {
    if (binding.value === true) el.focus();
  },
};
</script>

任何以v开头的驼峰式命名的变量都可以当作自定义指令使用,例如vFocus在模板中以v-focus的形式使用

四、全局自定义指令

import { createApp } from "vue";
const app = createApp(App);
app.directive("focus", {
  mounted(el, binding) {
    if (binding.value === true) el.focus();
  },
});

五、简化形式(函数式指令)

当仅需要在mounted和updated上实现相同的行为,不需要使用到其他钩子函数时,可以直接用一个函数来定义指令

import { createApp } from "vue";
const app = createApp(App);
app.directive("focus", (el, binding) => {
  if (binding.value === true) el.focus();
});

六、实战

自定义权限控制指令

第一步:我们定义一个权限数组,代表当前登陆人有的所有权限(实际项目中一般从后端获取)

const userPermissions = ["add", "delete", "reset"];

第二步:自定义全局的权限控制的指令

const hasPermission = (needPermissions: string | string[]) => {
  //无权限要求时,默认显示
  if (!needPermissions) return true;
  
  //将传入的权限标识统一转为数组处理
  const needPerms = Array.isArray(needPermissions)
    ? needPermissions
    : [needPermissions];
    
  //传入的权限标识必须全部拥有才为true
  return needPerms.every((perm) => userPermissions.includes(perm));
};

app.directive("permission", (el, binding) => {
  const isShow = hasPermission(binding.value);
  if (!isShow && el) el.remove();
});

第三步:在需要权限控制的页面使用自定义指令控制权限

<template>
  <div v-permission="'add'">新增</div>
  <div v-permission="'delete'">删除</div>
  <div v-permission="'reset'">修改</div>
  <div v-permission="'find'">查找</div>
  <div v-permission="['add', 'delete']">新增和删除</div>
  <div v-permission="['reset', 'find']">修改和查找</div>
</template>

最后,验证结果如下

image.png