Vue 3 自定义指令详细使用指南
1. 基本结构
一个完整的自定义指令包含以下可选钩子函数:
javascript
const myDirective = {
// 指令第一次绑定到元素时调用(只调用一次)
created(el, binding, vnode, prevVnode) {},
// 元素插入父 DOM 前调用
beforeMount(el, binding, vnode, prevVnode) {},
// 元素插入父 DOM 后调用
mounted(el, binding, vnode, prevVnode) {},
// 父组件更新前调用
beforeUpdate(el, binding, vnode, prevVnode) {},
// 父组件和子组件都更新后调用
updated(el, binding, vnode, prevVnode) {},
// 父组件卸载前调用
beforeUnmount(el, binding, vnode, prevVnode) {},
// 父组件卸载后调用
unmounted(el, binding, vnode, prevVnode) {}
}
2.钩子函数参数

3.注册方式
3.1全局注册
javascript
// 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')
3.2 局部注册
javascript
// 在组件中
export default {
directives: {
focus: {
mounted(el) {
el.focus()
}
}
}
}
4.使用方式

5.实用示例
5.1权限控制指令
javascript
app.directive('permission', {
mounted(el, binding) {
const userPermissions = ['edit', 'view'] // 通常从store获取
if (!userPermissions.includes(binding.value)) {
el.style.display = 'none'
// 或者直接移除元素
// el.parentNode.removeChild(el)
}
}
})
5.2 防抖点击指令
javascript
app.directive('debounce-click', {
mounted(el, binding) {
const delay = binding.value || 500
let timer = null
el.addEventListener('click', () => {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
binding.arg && binding.arg()
}, delay)
})
},
unmounted(el) {
el.removeEventListener('click')
}
})
5.3 拖拽指令
javascript
app.directive('drag', {
mounted(el) {
let isDragging = false
let offsetX, offsetY
el.style.position = 'absolute'
el.style.cursor = 'move'
el.addEventListener('mousedown', (e) => {
isDragging = true
offsetX = e.clientX - el.getBoundingClientRect().left
offsetY = e.clientY - el.getBoundingClientRect().top
})
document.addEventListener('mousemove', (e) => {
if (!isDragging) return
el.style.left = e.clientX - offsetX + 'px'
el.style.top = e.clientY - offsetY + 'px'
})
document.addEventListener('mouseup', () => {
isDragging = false
})
}
})
5.4 图片懒加载指令
javascript
app.directive('lazy', {
mounted(el, binding) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
el.src = binding.value
observer.unobserve(el)
}
})
})
observer.observe(el)
}
})
6.注意事项
在 setup() 中定义的指令必须以 v 开头(如 vFocus),才能在模板中作为 v-focus 使用
指令必须从 setup() 中返回才能在模板中使用
对于需要清理的资源(如事件监听器),确保在 unmounted 钩子中进行清理
指令的 binding 参数是响应式的,但 el 不是
在 <script setup> 中定义的指令会自动暴露给模板,无需显式返回