阅读视图

发现新文章,点击刷新页面。

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

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

钩子函数 促发时机 常用参数
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

❌