Vue3拓展:自定义权限指令

一、实验目标

  1. 掌握 Vue3 自定义指令的 4 个核心生命周期钩子(created/mounted/updated/unmounted)及执行时机

  2. 独立封装1个高频业务指令(v-permission 权限控制),实现一次封装、全局复用

  3. 熟练运用指令、动态参数、修饰符扩展指令功能,适配复杂业务场景

  4. 掌握自定义指令的 全局注册、局部注册 方式,理解 Tree-Shaking 兼容方案,避免打包冗余

  5. 解决实际开发中 "重复 DOM 操作、业务逻辑散落在组件" 的痛点,提升代码复用性和可维护性

二、实验步骤

1. 指令 :v-permission(权限控制)

需求:根据用户角色控制元素显示 / 隐藏(支持多个角色、反向权限)。

(1)封装实现(src/directives/permission.ts

javascript 复制代码
import type { Directive, DirectiveBinding } from 'vue'

// 模拟全局用户角色(实际从 Pinia/本地存储获取)
const userRoles = ['admin', 'editor']

const permissionDirective: Directive = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    const { value: requiredRoles, modifiers } = binding
    // 1. 若指令无值,直接隐藏
    if (!requiredRoles || !Array.isArray(requiredRoles)) {
      el.style.display = 'none'
      return
    }
    // 2. 判断用户是否拥有所需角色(some:满足一个即可)
    const hasPermission = requiredRoles.some(role => userRoles.includes(role))
    // 3. modifiers.invert:反向权限(有角色则隐藏)
    if (modifiers.invert ? hasPermission : !hasPermission) {
      el.style.display = 'none'
    }
  }
}

export default permissionDirective

(2)全局注册

src/directives/index.ts 中统一导出指令:

javascript 复制代码
import type { App } from 'vue'
import permission from './permission'

// 指令映射表(key:指令名,value:指令实现)
const directives = {
  permission
}

// 全局注册所有指令
export const registerDirectives = (app: App) => {
  Object.entries(directives).forEach(([name, directive]) => {
    app.directive(name, directive)
  })
}

(3)在 src/main.ts 中调用注册:

javascript 复制代码
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import { registerDirectives } from './directives'


// 1. 创建 Pinia 实例(TS 自动推断为 Pinia 类型)
const pinia = createPinia()
// 2. 安装持久化插件
pinia.use(piniaPluginPersistedstate)
// 3. 全局注册 Pinia(Vue 实例类型自动适配)
const app = createApp(App).use(pinia)
registerDirectives(app)
app.mount('#app')

(3) 实验结果

(4)实验说明

permission.ts中的模拟部分可以修改测试

bash 复制代码
// 模拟全局用户角色(实际从 Pinia/本地存储获取)

const userRoles = ['admin', 'editor']

HelloWorld.vue中的逻辑也可以修改测试

bash 复制代码
<template>
  <!-- 只有 admin/editor 可见 -->
  <button v-permission="['admin', 'editor']">编辑按钮</button>
  <!-- 反向权限:admin 不可见 -->
  <button v-permission.invert="['admin']">普通用户按钮</button>
</template>

三、核心原理

(一)自定义指令的本质与工作流程

Vue3 自定义指令的核心是 "封装 DOM 操作逻辑",本质是一个包含生命周期钩子的对象。其工作流程如下:

  1. 注册阶段 :通过 app.directive(name, directive) 或局部注册,Vue 会将指令与指令名关联;

  2. 解析阶段 :模板编译时,Vue 识别 v-xxx 指令,将其与对应的 DOM 元素绑定;

  3. 执行阶段 :DOM 元素触发对应生命周期(如挂载、更新、卸载)时,Vue 调用指令的对应钩子函数,传入 el(DOM 元素)和 binding(参数对象);

  4. 销毁阶段 :元素卸载时,调用 unmounted 钩子,清理事件监听、定时器等,避免内存泄漏。

(二)关键 API 与参数解析

  1. 核心参数 DirectiveBinding

指令钩子的第二个参数 binding 包含指令的所有配置信息,类型定义如下:

javascript 复制代码
interface DirectiveBinding<T = any> {
  value: T;          // 指令值(如 v-debounce="handleClick" 中的 handleClick)
  oldValue: T | null; // 上一次的指令值(仅 updated 钩子可用)
  arg?: string;      // 动态参数(如 v-debounce:1000 中的 1000)
  modifiers: Record<string, boolean>; // 修饰符(如 v-permission.invert 中的 { invert: true })
  instance: ComponentPublicInstance | null; // 指令所在的组件实例
  dir: Directive;    // 指令本身的定义对象
}
  1. 生命周期钩子的设计逻辑
  • created:用于初始化准备(如存储初始状态),此时 DOM 尚未挂载,无法操作 el 的样式 / 事件;

  • mounted:核心钩子,DOM 已挂载,可安全执行 DOM 操作(如绑定事件、设置样式);

  • updated:组件更新时触发,用于同步指令状态(如指令值变化后更新 DOM);

  • unmounted:用于资源清理(如移除事件监听、销毁定时器、停止观察者),避免内存泄漏。

相关推荐
六月的可乐6 分钟前
【干货】小程序虚拟瀑布流探索小结
前端·react.js·小程序
techdashen13 分钟前
Rust 项目管理动态 — 2026 年 3 月
前端·人工智能·rust
智码看视界1 小时前
老梁聊全栈系列:Vue3核心与组合式API深度解析
javascript·vue.js·ecmascript
原则猫11 小时前
HOOKS 背后机制
前端
码语智行11 小时前
首页导航跳转功能深度解析-系统内和系统外
前端
阿猫的故乡12 小时前
Vue过渡动画从入门到装X:淡入淡出、滑动、列表动画、第三方库全搞定
前端·javascript·vue.js
裕波12 小时前
Vue&ViteConf 2026 将于 7 月 18 日在上海举办,尤雨溪将现场发表主题演讲
vue.js·vite
IManiy12 小时前
总结之Vibe Coding前端骨架
前端
JS菌12 小时前
AI Agent 沙箱双层防护体系:从权限过滤到内核隔离的完整实现
前端·人工智能·后端
Aphasia31112 小时前
从输入URL到页面展示全流程
前端·面试