# Vue3教程 - 9 自定义指令
在前面我们使用了很多的 Vue 的内置指令来完成功能,例如 v-bind
、v-show
、v-text
。
我们也可以自定义指令来完成想要的功能,如果想要实现自定义指令,就要对 DOM 进行操作,其实内置指令也是这么做的。
下面通过一个简单的功能来熟悉一下自定义指令。
实现这样一个功能:
v-text
指令是将内容显示在标签中,我们编写一个功能,在内容前面加上 逗比
。
# 9.1 全局指令
在 Vue 3 中,自定义指令的定义方式与 Vue 2 略有不同。
使用 app.directive
来定义全局指令。第一个参数是指令的名称,第二个参数是一个对象,对象中定义了一些回调方法,常用的有 beforeMount
、mounted
、beforeUpdate
、updated
、beforeUnmount
、unmounted
。
mounted
函数会在 DOM 元素被插入到页面中的时候回调。beforeMount
的函数是在元素加载到内存中就会回调,所以beforeMount
函数在mounted
函数之前执行。回调函数的第一个参数都是绑定指令的那个元素。
# 1 定义指令
可以在项目的入口文件 main.ts
中注册全局指令,具体实现:
import { createApp } from "vue";
import App from "./App.vue";
const app = createApp(App);
// 定义全局指令
app.directive("doubi", {
// 在每个函数中,第一个参数都是element,表示被绑定了指令的那个DOM元素,这个element参数,是一个原生的JS对象
// 第二个参数 binding 提供了关于指令绑定的信息。
beforeMount(element, binding) {
// 此时元素刚绑定了指令,还没有插入到DOM中去
console.log("执行beforeMount函数:", element, binding);
},
// mounted表示元素插入到DOM中的时候会执行mounted函数,只执行一次
mounted(element, binding) {
console.log("执行mounted函数:", element, binding);
element.innerText = "逗比: " + binding.value; // 初始化,前面添加上逗比
},
// 当模板中有数据更新的时候,即使不是当前指令用到的数据,都会执行updated,可能会触发多次
updated(element, binding) {
console.log("执行updated函数:", element, binding);
element.innerText = "逗比: " + binding.value; // 数据更新后,前面添加上逗比
},
});
app.mount("#app");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
app.directive()
有两个参数:
参数1:指令的名称,注意,在定义的时候,指令的名称前面,不需要加
v-
前缀,但是在调用的时候,必须在指令名称前加上v-
前缀来进行调用。参数2:是一个对象,这个对象身上有一些指令相关的回调函数,这些函数可以在特定的阶段执行相关的操作。
指令的回调函数有两个参数:
- 第一个参数:是指令所绑定的DOM元素,它是
HTMLElement
类型,通过这个参数,你可以直接访问和操作DOM。例如,你可以改变元素的样式、属性、或者监听事件等。 - 第二个参数:是一个对象,它包含了关于指令的详细信息,如指令的值、参数、修饰符等。
# 2 使用指令
在组件中使用指令:
<template>
<div>
<!-- 2.使用指令 -->
<div v-doubi="msg"></div>
<!-- 其他数据 -->
<div v-text="count"></div>
<button @click="changeData">改变data</button>
</div>
</template>
<!-- setup -->
<script lang="ts" setup>
import { ref } from 'vue';
let msg = ref("Hello");
let count = ref(0);
function changeData() {
count.value++;
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
上面 v-doubi="msg"
使用指令。
需要注意:当模板中有数据更新的时候,即使不是当前指令用到的数据,都会执行 updated
。
执行效果:
# 9.2 定义私有指令
私有指令只能在当前组件中定义是使用。
以 v
开头的驼峰式命名的变量都可以被用作一个自定义指令。
<template>
<div>
<!-- 2.使用指令 -->
<div v-doubi="msg"></div>
<!-- 其他数据 -->
<div v-text="count"></div>
<button @click="changeData">改变data</button>
</div>
</template>
<!-- setup -->
<script lang="ts" setup>
import { ref } from 'vue';
let msg = ref("Hello");
let count = ref(0);
function changeData() {
count.value++;
}
// 在模板中启用 v-focus
const vDoubi = {
// 在每个函数中,第一个参数都是element,表示被绑定了指令的那个DOM元素,这个element参数,是一个原生的JS对象
// 第二个参数 binding 提供了关于指令绑定的信息。
beforeMount(element: any, binding: any) {
// 此时元素刚绑定了指令,还没有插入到DOM中去
console.log("执行beforeMount函数:", element, binding);
},
// mounted表示元素插入到DOM中的时候会执行mounted函数,只执行一次
mounted(element: { innerText: string; }, binding: { value: string; }) {
console.log("执行mounted函数:", element, binding);
element.innerText = "逗比: " + binding.value; // 初始化,前面添加上逗比
},
// 当模板中有数据更新的时候,即使不是当前指令用到的数据,都会执行updated,可能会触发多次
updated(element: { innerText: string; }, binding: { value: string; }) {
console.log("执行updated函数:", element, binding);
element.innerText = "逗比: " + binding.value; // 数据更新后,前面添加上逗比
},
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
上面 vDoubi
就是一个指令,
# 9.3 指令传递参数
在上面我们创建的自定义指令,传递的参数是 data 中的参数,如果需要,还可以通过如下形式传递参数都可以
# 1 不传递参数
如果不需要参数,还可以不传递参数。
<input type="text" v-doubi>
# 2 传递字符串参数
字符串参数需要使用''括起来,因为如果不括起来,会认为是vue中定义的属性;如果是数字就不需要添加单引号了。
<input type="text" v-doubi="'green'">
# 3 传递多个参数
如果想传递多个参数可以传递一个对象:
参数传递:
<input type="text" v-doubi="{'color1':'red', 'color2':'green'}">
参数获取:
binding.value.color1
需要注意,指令回调函数的参数,除了第一个参数 element
之外,其他参数都应该是只读的,切勿进行修改。
# 9.4 指令回调钩子函数的简写
在大多数情况下,我们可能想在 mounted
和 updated
钩子上做重复动作,并且不想关心其他的钩子函数,可以简写成如下:
// 自定义全局指令
app.directive('doubi', (element, binding) => {
console.log("执行函数:", element, binding);
element.innerText = "逗比: " + binding.value;
});
// 自定义私有指令
// 在模板中启用 v-doubi 指令
const vDoubi = (element: HTMLElement, binding: { value: string }) => {
console.log("执行函数:", element, binding);
element.innerText = "逗比: " + binding.value;
};
2
3
4
5
6
7
8
9
10
11
12
简写的方式相当于在 mounted
和 updated
两个钩子方法中都写了相同的代码。