VUE 自定义指令

2 阅读3分钟

Vue 自定义指令的使用方法

Vue 自定义指令(Directives)用于 直接操作 DOM,它们的功能类似于 Vue 内置指令(如 v-ifv-showv-model),但可以自定义行为,比如 权限控制、输入限制、拖拽、自动聚焦等


1. 自定义指令的基本用法

(1)局部指令

Vue 组件 内部定义和使用:

<script setup>
import { onMounted } from "vue";

const vFocus = {
  mounted(el) {
    el.focus(); // 指令绑定的元素会自动获取焦点
  }
};
</script>

<template>
  <input v-focus placeholder="自动聚焦输入框" />
</template>

📌 作用:输入框在页面加载时自动获取焦点。


(2)全局指令

main.js全局指令文件 中注册:

import { createApp } from "vue";
import App from "./App.vue";

const app = createApp(App);

// 注册全局指令
app.directive("focus", {
  mounted(el) {
    el.focus();
  }
});

app.mount("#app");

然后 在任何组件中使用

<input v-focus placeholder="自动聚焦输入框" />

2. 自定义指令的生命周期钩子

Vue 自定义指令支持多个 生命周期钩子

钩子触发时机
created指令绑定到元素上(仅调用一次)。
beforeMount在元素插入 DOM 之前调用(适用于初始化逻辑)。
mounted元素插入 DOM 后调用(适用于操作 DOM)。
beforeUpdate绑定元素的父组件更新前调用(适用于动态内容)。
updated绑定元素的父组件更新后调用(适用于动态内容)。
beforeUnmount元素被卸载前调用(适用于清理事件)。
unmounted元素被卸载后调用(适用于清理 DOM 资源)。

📌 示例:指令完整写法

app.directive("demo", {
  created(el, binding) {
    console.log("created:", binding.value);
  },
  beforeMount(el) {
    console.log("beforeMount");
  },
  mounted(el) {
    console.log("mounted");
  },
  beforeUpdate(el) {
    console.log("beforeUpdate");
  },
  updated(el) {
    console.log("updated");
  },
  beforeUnmount(el) {
    console.log("beforeUnmount");
  },
  unmounted(el) {
    console.log("unmounted");
  }
});

然后在组件中:

<p v-demo="'hello'">自定义指令测试</p>

控制台会输出 created: hellomounted 等日志。


3. 自定义指令的参数与动态值

(1)指令绑定值

指令可以接收一个值,如:

<input v-focus="true" />
app.directive("focus", {
  mounted(el, binding) {
    if (binding.value) {
      el.focus(); // 只有当传入值为 true 时才聚焦
    }
  }
});

(2)指令修饰符

修饰符是指令中的 . 号后缀,类似 v-model.trim

<input v-uppercase.focus />
app.directive("uppercase", {
  mounted(el, binding) {
    el.addEventListener("input", () => {
      el.value = el.value.toUpperCase(); // 转大写
    });

    if (binding.modifiers.focus) {
      el.focus(); // 如果有 .focus 修饰符,则自动聚焦
    }
  }
});

4. 实战案例

(1)RBAC 权限控制指令

import { useUserStore } from "@/store/user";

export default {
  mounted(el, binding) {
    const userStore = useUserStore();
    const permissions = userStore.permissions || [];
    const requiredPermissions = binding.value;

    if (!permissions.includes(requiredPermissions)) {
      el.parentNode && el.parentNode.removeChild(el);
    }
  }
};

📌 用法

<button v-permission="'delete'">删除</button>

如果用户没有 "delete" 权限,按钮会被移除


(2)图片懒加载 v-lazy

app.directive("lazy", {
  mounted(el, binding) {
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        el.src = binding.value; // 加载图片
        observer.unobserve(el); // 只触发一次
      }
    });
    observer.observe(el);
  }
});

📌 用法

<img v-lazy="'https://example.com/image.jpg'" />

只有图片进入视口才会加载提高性能


(3)防抖输入框 v-debounce

app.directive("debounce", {
  mounted(el, binding) {
    let timer;
    el.addEventListener("input", () => {
      clearTimeout(timer);
      timer = setTimeout(() => {
        binding.value(); // 触发回调
      }, 500);
    });
  }
});

📌 用法

<input v-debounce="onInput" />
function onInput() {
  console.log("输入完成!");
}

输入停止 500ms 后才触发回调,避免频繁触发 API。


总结

基本使用

  • 局部注册:直接在组件 setup() 内定义。
  • 全局注册:在 main.js 中注册,全项目可用

生命周期钩子

  • mounted:操作 DOM。
  • updated:动态更新。

应用场景

  • 权限控制v-permission
  • 图片懒加载v-lazy
  • 输入防抖v-debounce
  • 自动聚焦v-focus
  • 文本转换v-uppercase

🚀 自定义指令可以极大提升 Vue 开发的可复用性!