Vue3 - 自定义指令封装
- 一. 自定义指令封装
- 1.1 全局/局部注册自定义聚焦指令
- 1.2 自定义指令相关参数
- 1.3 自定义指令参数传递
- 二. 总结
一. 自定义指令封装
vue中有很多内置的指令,我们一般在开发中也经常用到,比如v-if,v-for等等。那么本篇文章就来讲一讲如何自定义指令。
我们先来看下一个简单的功能,我们画一个简单的页面,然后页面里面有一个文本框:
<template>
<div class="border">
<h1 >我是父组件</h1>
文本框:<inpu type="text">
</div>
</template>
<script setup>
</script>
<style scoped>
.border {
border: 1px solid;
width: 400px;
height: 200px;
}
</style>
运行结果如下:

那么如果我希望页面刚进入,就能聚焦到这个文本框中,该怎么做?我们这里就使用自定义指令的功能来完成。
1.1 全局/局部注册自定义聚焦指令
首先我们说下局部的定义方式,我们在首页中添加以下代码:
<script setup>
const vFocus = {
mounted: (el) => {
console.log('mounted');
el.focus();
},
};
</script>
然后再inpu标签上添加指令:<input v-focus type="text" />,那么页面刷新一下,效果如下:可见已经聚焦到文本框中,并且输出了对应的内容。

紧接着再来说下全局的注册,主要在main.ts入口文件中使用directive函数进行注册。这样任何一个组件中都可以使用指令:v-focus。
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
createApp(App)
.directive('focus', {
// 当被绑定的元素挂载到 DOM 中时
mounted(el) {
// 聚焦元素
el.focus()
}
})
.mount('#app')
讲到这里,其实我并没有对指令的定义做出太多的解释,先把这个功能代码贴出来,接下来开始细讲。
1.2 自定义指令相关参数
大家可以从案例中看到,在定义自定义指令的时候,我们定义了一个mounted函数,其实除了他还有几个钩子函数。
created:在绑定元素的attribute前或事件监听器应用前调用。beforeMount:当指令第一次绑定到元素上并且在父组件被挂载前调用。mounted:在绑定元素的父组件及他自己的所有子节点都挂载完成后调用,一般我们自定义指令的逻辑都写在这里。beforeUpdate:绑定元素的父组件及他自己的所有子节点都更新前调用。updated:在绑定元素的父组件及他自己的所有子节点都更新后调用。beforeUnmount:在父组件被卸载前调用。unmounted:当指令和元素已经解除绑定并且父组件也已经被卸载的时候调用。
同样,我们还注意到,我们定义mounted钩子函数的时候,还传入了一个参数el,除此之外,还有三个参数,一共4个。
el(读写):指令所绑定的元素,可以直接操作DOM。binding(只读):通过自定义指令传递的参数都在这里。vnode(只读):Vue编译生成的虚拟节点。oldVnode(只读):上一个虚拟节点,仅仅在update和componentUpdated钩子函数中才可以使用。
1.3 自定义指令参数传递
我们来看下这个案例:
<template>
<div class="border">
<h2>我是父组件</h2>
<button v-onceClick:{name:myName,age:10}="1">按钮1秒</button>
<br>
<button v-onceClick:{name:myName,age:10}="3">按钮3秒</button>
</div>
</template>
<script setup>
const myName = "ljj";
const vOnceClick = {
mounted: (el, binding, vnode) => {
el.addEventListener("click", () => {
if (!el.disabled) {
el.disabled = true;
let time = binding.value * 1000;
setTimeout(() => {
el.disabled = false;
}, time);
}
console.log(binding.value,binding.arg)
});
console.log(vnode)
},
};
</script>
<style scoped>
.border {
border: 1px solid;
width: 400px;
height: 200px;
}
</style>
效果如下:

我们可以看到,首先打印的是Vue编译后的虚拟节点相关信息。之后基本上同时点击了两个按钮。一个置灰了1秒,一个置灰了3秒。符合代码编写。
我们把这段代码拆分开来说:v-onceClick:{name:myName,age:10}="3"
- 冒号后面的是引入的值:
{name:myName,age:10}这块部分,竟然是一个字符串,我们代码里面定义了myName变量,值是ljj。但是从输出结果来看,他并不是我们期望的。但是我们可以从binding.arg中拿到这个值。 - 我们可以从
binding.value中拿到="3"这部分的数据。
后来经过我的测验,针对第一点,我们这样改,传入一个单对象,使用中括号:
<button v-onceClick:[{name:myName,age:10}]="1">按钮1秒</button>
<br />
<button v-onceClick:[myName]="3">按钮3秒</button>
结果如下:

二. 总结
总结下自定义指令的封装相关知识点:
- 自定义指令,我们一般需要定义一个对象,里面包含一个
mounted函数,我们主要在这个函数中,对传入的el参数,操作DOM节点。编写自己的业务逻辑即可。 - 如果希望往指令函数中传入相关的参数,可以通过
v-指令名称:[Obj]=val的写法来完成。 Obj则由mounted这样钩子函数的第二个参数binding对象中获得,即biding.arg。val则通过biding.value来获得。- 注意相关钩子函数中,一般我们只操作第一个参数
el来控制DOM节点,其他参数一般是只读的。 - 一般我们命名自定义指令
const v指令名称 = {},Vue3写法中v前缀一定要有,使用的时候则由v-指令名称来指定。首字母大小写不影响。例如定义指令函数:vFocus,那么使用的时候v-focus或者v-Focus都可。



















