vue自定义指令

Vue 自定义指令(Custom Directives)是一种扩展 Vue 功能的方式,允许你直接操作 DOM 元素,用于处理一些常见的 DOM 操作逻辑(如聚焦、权限控制、动画等)。

自定义指令的基本结构

自定义指令可以注册为全局指令或局部指令,包含一系列钩子函数(类似组件生命周期)。

1. 全局注册
javascript 复制代码
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})
2. 局部注册
javascript 复制代码
export default {
  directives: {
    focus: {
      // 指令的定义
      inserted: function (el) {
        el.focus()
      }
    }
  }
}
使用方式
vue 复制代码
<template>
  <input v-focus />
</template>

指令的钩子函数

指令有 5 个钩子函数(Vue 2):

钩子函数 说明
bind 只调用一次,指令第一次绑定到元素时调用
inserted 被绑定元素插入父节点时调用
update 所在组件的 VNode 更新时调用(可能发生在子 VNode 更新前)
componentUpdated 所在组件的 VNode 及其子 VNode 全部更新后调用
unbind 只调用一次,指令与元素解绑时调用

钩子函数参数

  • el:指令所绑定的元素,可以直接操作 DOM
  • binding:一个对象,包含指令相关信息(如 namevalueexpression 等)
  • vnode:Vue 编译生成的虚拟节点
  • oldVnode:上一个虚拟节点(仅在 updatecomponentUpdated 钩子中可用)

实用示例

1. 权限控制指令(v-permission)
javascript 复制代码
// 全局注册 v-permission
Vue.directive('permission', {
  inserted(el, binding) {
    // 获取用户权限列表(实际项目中可能从 Vuex 或接口获取)
    const userPermissions = ['edit', 'delete']
    // 获取指令绑定的值(如 v-permission="['delete']")
    const requiredPermissions = binding.value
    
    // 检查是否有权限,无权限则移除元素
    const hasPermission = requiredPermissions.some(perm => 
      userPermissions.includes(perm)
    )
    
    if (!hasPermission) {
      el.parentNode && el.parentNode.removeChild(el)
    }
  }
})
vue 复制代码
<!-- 只有拥有 delete 权限的用户才会看到该按钮 -->
<button v-permission="['delete']">删除</button>
2. 防抖指令(v-debounce)
javascript 复制代码
Vue.directive('debounce', {
  bind(el, binding) {
    const { value, arg = 500 } = binding // arg 为防抖时间,默认 500ms
    let timer = null
    
    el.addEventListener('click', () => {
      if (timer) clearTimeout(timer)
      timer = setTimeout(() => {
        value() // 执行绑定的方法
      }, arg)
    })
  }
})
vue 复制代码
<!-- 点击后 1000ms 才执行 handleClick 方法 -->
<button v-debounce:[1000]="handleClick">提交</button>
3. Vue 3 中的自定义指令

Vue 3 中指令钩子函数有所调整,更贴近组合式 API:

javascript 复制代码
// Vue 3 全局注册
import { createApp } from 'vue'
const app = createApp(App)

app.directive('focus', {
  // 在元素挂载后执行(替代 Vue 2 的 inserted)
  mounted(el) {
    el.focus()
  }
})

Vue 3 指令钩子:createdbeforeMountmountedbeforeUpdateupdatedbeforeUnmountunmounted

动态指令参数

指令可以接收动态参数,使指令更灵活:

vue 复制代码
<!-- 动态设置背景色 -->
<div v-bg:[color]="'red'"></div>

<script>
Vue.directive('bg', {
  bind(el, binding) {
    // binding.arg 为动态参数(color 的值)
    // binding.value 为指令值('red')
    el.style[binding.arg] = binding.value
  }
})

export default {
  data() {
    return { color: 'backgroundColor' }
  }
}
</script>

注意事项

  1. 自定义指令主要用于底层 DOM 操作,若能通过组件或 props 实现的功能,优先使用组件
  2. 避免在指令中过度处理复杂逻辑,保持指令单一职责
  3. Vue 3 中指令的钩子函数与组件生命周期更一致,使用时注意区分

通过自定义指令,可以封装通用的 DOM 操作逻辑,提高代码复用性。

vue3的自定义指令钩子函数

在 Vue 3 中,自定义指令的钩子函数进行了调整,命名更贴近组件的生命周期,使其更易于理解和使用。以下是 Vue 3 中自定义指令的钩子函数及详细说明:

Vue 3 自定义指令的钩子函数

Vue 3 提供了 7 个指令钩子函数,按执行顺序排列如下:

钩子函数 触发时机
created 指令绑定到元素上且组件的属性或事件监听器被应用之前调用(很少使用)
beforeMount 指令绑定的元素被挂载到 DOM 之前调用
mounted 指令绑定的元素被挂载到 DOM 后调用(最常用,替代 Vue 2 的 inserted
beforeUpdate 指令所在组件的 VNode 更新前调用(可能发生在子 VNode 更新前)
updated 指令所在组件的 VNode 及其子 VNode 全部更新后调用
beforeUnmount 指令绑定的元素从 DOM 卸载前调用
unmounted 指令绑定的元素从 DOM 卸载后调用(替代 Vue 2 的 unbind

钩子函数的参数

每个钩子函数都接收以下 4 个参数(与 Vue 2 类似,但部分属性有调整):

  • el:指令所绑定的 DOM 元素,可直接操作 DOM

复制代码
  binding

:包含指令信息的对象,结构如下:

  • value:指令的绑定值(如 v-directive="123" 中的 123

  • oldValue:指令绑定的前一个值(仅在 beforeUpdateupdated 中可用)

  • arg:指令的参数(如 v-directive:foo 中的 foo

  • modifiers:指令的修饰符对象(如 v-directive.foo.bar{ foo: true, bar: true }

  • instance:使用该指令的组件实例

  • dir:指令的定义对象(包含钩子函数等)

  • vnode:Vue 编译生成的虚拟节点

  • prevVnode:上一个虚拟节点(仅在 beforeUpdateupdated 中可用)

示例:实现一个 Vue 3 自定义指令

以下是一个完整示例

vue 复制代码
<template>
  <!-- 使用自定义指令 -->
  <button v-copy="copyText" v-copy:success="onCopySuccess">
    点击复制
  </button>
</template>

<script setup>
import { ref } from 'vue'
import { copyDirective } from './directives'

// 注册局部指令
const directives = {
  copy: copyDirective
}

// 要复制的文本
const copyText = ref('这是要复制的内容')

// 复制成功的回调
const onCopySuccess = (text) => {
  alert(`复制成功:${text}`)
}
</script>

<!-- directives.js -->
<script>
export const copyDirective = {
  // 元素挂载后
  mounted(el, binding) {
    // 存储要复制的文本和回调函数
    el.copyText = binding.value
    el.successCallback = binding.arg === 'success' ? binding.value : null

    // 点击事件处理函数
    el.handleClick = () => {
      // 复制文本到剪贴板
      navigator.clipboard.writeText(el.copyText)
        .then(() => {
          // 触发成功回调
          if (el.successCallback && typeof el.successCallback === 'function') {
            el.successCallback(el.copyText)
          }
        })
        .catch(err => {
          console.error('复制失败:', err)
        })
    }

    // 绑定点击事件
    el.addEventListener('click', el.handleClick)
  },

  // 组件更新时(值可能变化)
  updated(el, binding) {
    // 更新存储的文本和回调
    el.copyText = binding.value
    if (binding.arg === 'success') {
      el.successCallback = binding.value
    }
  },

  // 元素卸载前
  beforeUnmount(el) {
    // 移除事件监听,避免内存泄漏
    el.removeEventListener('click', el.handleClick)
  }
}
</script>

关键变化与注意事项

  1. 钩子命名更直观

    mounted 替代 Vue 2 的 inserted(元素挂载到 DOM 后触发),用 unmounted 替代 unbind(元素卸载后触发),更符合组件生命周期的命名习惯。

  2. 支持组合式 API

    <script setup> 中,局部指令通过 directives 对象注册,全局指令通过 app.directive() 注册(如 app.directive('copy', copyDirective))。

  3. 参数增强

    binding.instance 可以直接访问使用指令的组件实例,方便获取组件内的数据或方法。

  4. 清理逻辑

    需在 beforeUnmountunmounted 中移除事件监听、定时器等,避免内存泄漏(如示例中移除点击事件)。

常见使用场景

  • 操作 DOM(如自动聚焦 v-focus、滚动加载 v-infinite-scroll
  • 权限控制(如 v-permission 决定元素是否显示)
  • 交互增强(如 v-longpress 长按指令、v-debounce 防抖指令)

Vue 3 的自定义指令钩子设计更符合直觉,同时保留了灵活操作 DOM 的能力,是扩展 Vue 功能的重要方式。

相关推荐
艾小码17 小时前
Vue 3 defineProps 与 defineEmits 深度解析
前端·javascript·vue.js
前端炒粉20 小时前
35.LRU 缓存
开发语言·javascript·数据结构·算法·缓存·js
巧克力芋泥包21 小时前
前端使用阿里云图形验证码;并且与安卓进行交互
android·前端·阿里云
G***E3161 天前
前端GraphQLAPI
前端
lumi.1 天前
Vue + Element Plus 实现AI文档解析与问答功能(含详细注释+核心逻辑解析)
前端·javascript·vue.js·人工智能
z***I3941 天前
VueGraphQLAPI
前端
S***t7141 天前
Vue面试经验
javascript·vue.js·面试
粉末的沉淀1 天前
css:制作带边框的气泡框
前端·javascript·css
p***h6431 天前
JavaScript在Node.js中的异步编程
开发语言·javascript·node.js
N***73851 天前
Vue网络编程详解
前端·javascript·vue.js