一、自定义指令基础概念
官方文档:自定义指令
1.1 什么是自定义指令?
Vue自定义指令是对原生DOM操作的高级封装,用于扩展HTML元素的功能。它允许开发者创建可复用的DOM行为,主要应用于以下场景:
- DOM底层操作(如聚焦、拖拽)
- 集成第三方DOM库
- 创建可视化特效
1.2 生命周期钩子
钩子函数 | 触发时机 | 典型应用场景 |
---|---|---|
created | 元素属性初始化时 | 访问初始化属性值 |
beforeMount | 元素插入DOM前 | 预加载资源 |
mounted | 元素插入DOM后 | DOM操作(最常用) |
beforeUpdate | 绑定值更新前 | 保存旧状态 |
updated | 绑定值更新后 | 响应数据变化 |
beforeUnmount | 元素卸载前 | 清理定时器 |
unmounted | 元素卸载后 | 移除事件监听 |
二、指令注册方式详解
2.1 全局注册
javascript
// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// 方式1:直接注册
app.directive('focus', { //focus指令
mounted(el) { //mounted时生效
el.focus()
}
})
// 方式2:模块化注册 //代码更加优雅
import draggable from './directives/draggable'
app.directive('draggable', draggable)
2.2 局部注册(组件级)
vue
<script setup>
// 方式1:函数式指令
const vColor = (el, binding) => {
el.style.color = binding.value
}
// 方式2:对象式指令
const vHighlight = {
mounted(el, binding) {
el.style.backgroundColor = binding.value
},
updated(el, binding) {
el.style.backgroundColor = binding.value
}
}
</script>
三、实战案例解析
3.1 案例一:元素拖拽指令
3.1.1. 定义指令
js
// 定义自定义指令
export default {
mounted(el) {
// 鼠标放上去时,改变鼠标样式为"move"
el.style.cursor = 'move'
el.style.position = 'relative'
// 监听鼠标按下事件
el.onmousedown = function(e) {
// 获取鼠标按下时相对元素的偏移
let disX = e.pageX - el.offsetLeft
let disY = e.pageY - el.offsetTop
// 监听鼠标移动事件
document.onmousemove = function(e) {
let x = e.pageX - disX
let y = e.pageY - disY
// 边界检测
let maxX = document.body.clientWidth - el.offsetWidth
let maxY = document.body.clientHeight - el.offsetHeight
// 限制元素在页面中的最大和最小位置
if (x < 0) x = 0
if (x > maxX) x = maxX
if (y < 0) y = 0
if (y > maxY) y = maxY
// 设置元素的新位置
el.style.left = `${x}px`
el.style.top = `${y}px`
}
// 监听鼠标释放事件
document.onmouseup = function() {
// 取消事件
document.onmousemove = null
document.onmouseup = null
}
}
}
}
3.1.2. 注册指令
指令的定义需要一个install
函数,该函数用于注册指令到Vue实例中。Vue会调用install
函数来将指令注册到全局或局部。
js
// ./command/index.js'
import Draggable from './draggable.js'
// 统一注册
const directive = {
Draggable
//...
//...
}
export default {
install(app) {
// 注册自定义指令
Object.keys(directive).forEach(key => {
app.directive(key, directive[key]) //指令需要通过`app.directive`来注册。
})
}
}
然后在main.js中挂载。
js
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import Directives from './command/index.js'
const app = createApp(App)
app.use(Directives) // 全局注册 // 注册指令use调用了install 函数,触发注册
app.mount('#app')
3.1.3. 在组件中使用指令
自定义指令注册后,你就可以在模板中使用它了。假设你创建了一个v-draggable
指令来使元素可拖拽,下面是如何使用它的示例:
vue
<template>
<div class="box" v-draggable></div>
</template>
<script setup>
// 这里不需要特别的代码,因为指令已经在全局注册过
</script>
<style lang="css" scoped>
.box {
width: 100px;
height: 100px;
background-color: #f00;
}
</style>
3.2 案例二:动态颜色指令
javascript
// 对象式写法(推荐)
export default {
// el:该指令绑定在哪个元素上 binding:指令的相关信息,包含该指令绑定的值
mounted(el, binding) {
updateColor(el, binding.value);
},
updated(el, binding) {
updateColor(el, binding.value);
}
}
// 函数式写法(同时触发mounted和updated)
// export default (el, binding) => {
// updateColor(el, binding.value)
// }
function updateColor(el, value) {
const length = value?.length || 0;
if (length <= 5) {
el.style.color = 'green';
} else if (length <= 10) {
el.style.color = 'goldenrod';
} else {
el.style.color = 'red';
}
}
3.1.3. 使用示例
vue
<template>
<div class="input-group">
<input
type="text"
v-model="inputVal"
placeholder="输入内容观察颜色变化"
>
<h3 v-highlight="inputVal">{{ inputVal }}</h3>
</div>
</template>
<script setup>
import { ref } from 'vue';
const inputVal = ref('');
</script>
<style>
.input-group {
margin: 20px;
padding: 15px;
border: 1px solid #eee;
}
h3 {
transition: color 0.3s;
padding: 10px;
border-radius: 4px;
}
</style>