Vue 3 自定义指令:用 directive 封装权限控制与按钮防抖

test12026-09-140 次阅读

指令的本质

Vue 的指令是“带副作用的 DOM 行为封装”。和组件解决“渲染什么”不同,指令解决“这个 DOM 元素挂载后要做点什么”——权限裁剪、事件节流、自动聚焦都是它的典型舞台。复用逻辑时,指令比混入组件模板更轻。

权限指令 v-permission

把“用户是否拥有某权限”的判断收敛进一个指令,模板里只写权限点,没权限的按钮直接不渲染,避免在每个页面手写判断。

import type { Directive, DirectiveBinding } from "vue";

// 假设登录后把权限数组挂到全局
function getUserPermissions(): string[] {
  return (window as any).__permissions ?? [];
}

export const permission: Directive<HTMLElement, string | string[]> = {
  mounted(el, binding: DirectiveBinding<string | string[]>) {
    const required = Array.isArray(binding.value)
      ? binding.value
      : [binding.value];
    const owned = getUserPermissions();
    const ok = required.every((p) => owned.includes(p));
    if (!ok) {
      el.parentNode?.removeChild(el);
    }
  },
};

防重复点击指令 v-debounce-click

提交类按钮最怕用户连点导致重复请求。用一个捕获阶段的 click 指令,在锁定期间吞掉后续点击,比在每个 handler 里手写锁更省心。

import type { Directive } from "vue";

export const debounceClick: Directive<HTMLButtonElement, number> = {
  mounted(el, binding) {
    const wait = binding.value || 500;
    let lock = false;
    const handler = (e: Event) => {
      if (lock) {
        e.stopImmediatePropagation();
        e.preventDefault();
        return;
      }
      lock = true;
      setTimeout(() => {
        lock = false;
      }, wait);
    };
    el.addEventListener("click", handler, true);
    (el as any).__handler = handler;
  },
  unmounted(el) {
    el.removeEventListener("click", (el as any).__handler, true);
  },
};

全局注册

import { createApp } from "vue";
import App from "./App.vue";
import { permission } from "./directives/permission";
import { debounceClick } from "./directives/debounceClick";

const app = createApp(App);
app.directive("permission", permission);
app.directive("debounce-click", debounceClick);
app.mount("#app");

在模板里使用

<template>
  <button v-permission="'order:delete'" @click="remove">删除订单</button>
  <button v-debounce-click="800" @click="submit">提交</button>
</template>

经验清单

  • 指令适合“横切”多个元素的通用行为;单一业务的逻辑还是放在组件里更清楚。
  • 需要随响应式数据变化而更新的行为,用 updated 钩子,而不只是 mounted。
  • 指令里挂到 el 上的私有字段(如上例 __handler)要在 unmounted 里清理,避免内存泄漏。
  • 权限相关的指令只做“展示层裁剪”,服务端仍必须做真正的鉴权。
T

test1

文章作者

指令的本质 Vue 的指令是“带副作用的 DOM 行为封装”。和组件解决“渲染什么”不同,指令解决“这个 DOM 元素...

分类
技术
发布时间
2026-09-14
字数
约 2322 字
阅读
0 次