什么是Vue3自定义指令?
Vue3自定义指令是一种强大的功能,允许开发者直接操作DOM元素。与组件不同,指令更适合用于低级别的DOM操作。
自定义指令可以用于各种场景,如表单验证、图片懒加载、权限控制、动画效果等。Vue3中的指令API与Vue2相比有了一些变化,但核心概念保持一致。
提示: 指令特别适合封装那些需要在多个组件中重复使用的DOM操作逻辑。
基础自定义指令
指令注册
在Vue3中注册全局指令和局部指令的方法:
// 全局指令
app.directive('focus', {
mounted(el) {
el.focus()
}
})
// 局部指令
const myDirective = {
mounted(el, binding) {
// 指令逻辑
}
}
指令生命周期
Vue3指令的生命周期钩子:
- beforeMount - 元素插入DOM前调用
- mounted - 元素插入DOM后调用
- beforeUpdate - 元素更新前调用
- updated - 元素更新后调用
- beforeUnmount - 元素卸载前调用
- unmounted - 元素卸载后调用
指令参数
指令可以接收多种参数:
绑定值
<div v-my-directive="someValue"></div>
// 在指令中通过binding.value访问
mounted(el, binding) {
console.log(binding.value) // => someValue
}
参数和修饰符
<div v-my-directive:arg.modifier="value"></div>
// 在指令中访问
mounted(el, binding) {
console.log(binding.arg) // => "arg"
console.log(binding.modifiers) // => { modifier: true }
}
基础指令示例
1. 自动聚焦指令
app.directive('focus', {
mounted(el) {
el.focus()
}
})
2. 颜色指令
这段文字会变成红色
app.directive('color', {
mounted(el, binding) {
el.style.color = binding.value
}
})
高级自定义指令
动态参数指令
指令参数可以是动态的:
<div v-pin:[direction]="200">固定位置元素</div>
data() {
return {
direction: 'top'
}
}
app.directive('pin', {
mounted(el, binding) {
el.style.position = 'fixed'
const s = binding.arg || 'top'
el.style[s] = binding.value + 'px'
},
updated(el, binding) {
const s = binding.arg || 'top'
el.style[s] = binding.value + 'px'
}
})
函数简写
当只需要mounted和updated钩子时,可以使用简写:
app.directive('color', (el, binding) => {
el.style.color = binding.value
})
// 等同于
app.directive('color', {
mounted(el, binding) {
el.style.color = binding.value
},
updated(el, binding) {
el.style.color = binding.value
}
})
对象字面量
指令可以接收对象字面量:
HTML示例
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
指令实现
app.directive('demo', (el, binding) => {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "hello!"
})
高级指令示例
1. 权限控制指令
app.directive('permission', {
mounted(el, binding) {
const userRole = 'user' // 实际应从store或API获取
if (userRole !== binding.value) {
el.style.display = 'none'
}
}
})
2. 图片懒加载指令
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)
}
})
实战案例
1. 点击外部关闭
实现点击元素外部时触发关闭逻辑的指令。
2. 复制到剪贴板
一键复制文本到剪贴板的指令实现。
3. 拖拽指令
使元素可拖拽的自定义指令实现。
拖拽我试试
更多实用指令
1. 防抖指令
app.directive('debounce', {
mounted(el, binding) {
let timer
el.addEventListener('input', () => {
clearTimeout(timer)
timer = setTimeout(() => {
binding.value()
}, 500)
})
}
})
2. 长按指令
app.directive('longpress', {
mounted(el, binding) {
let pressTimer
const start = (e) => {
if (e.type === 'click' && e.button !== 0) return
pressTimer = setTimeout(() => {
binding.value()
}, 1000)
}
const cancel = () => clearTimeout(pressTimer)
el.addEventListener('mousedown', start)
el.addEventListener('touchstart', start)
el.addEventListener('click', cancel)
el.addEventListener('mouseout', cancel)
el.addEventListener('touchend', cancel)
el.addEventListener('touchcancel', cancel)
}
})
点击外部关闭演示
点击弹窗外部或关闭按钮可以关闭此弹窗。
这是通过v-click-outside指令实现的。