Vue3-自定义指令的使用
在Vue中有很多内置的指令,如:
v-if
,v-model
等等,除了这些内置的指令外,Vue还允许我们自己自定义指令。自定义指令主要是为了操作普通元素的底层dom,提高复用性。(不建议在组件上使用自定义指令) 一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情。
1. 基本使用
注册自定义指令接受两个参数,1:指令名称,2:配置对象。(配置对象是一个类似于组件的生命周期钩子的对象)
定义和注册:
app.directive("focus", {
mounted(el: HTMLInputElement) {
el.focus();
},
});
上面的例子就是注册了一个全局的focus
指令,这个指令会在DOM挂载后将input
元素聚焦。
使用:
<template>
<input v-focus>
</template>
全局注册,在所有的地方都可用,使用的方式:v-注册的名称
。如上面注册的指令名称是focus
,使用:v-focus
2.自定义指令的配置对象
配置对象是一个类似于组件的生命周期钩子的对象,里面有
mounted
,updated
等函数,会在组件的对应的生命周期中调用。
{
// 在绑定元素的 attribute 前
// 或事件监听器应用前调用
created(el, binding, vnode, prevVnode) {
// 下面会介绍各个参数的细节
},
// 在元素被插入到 DOM 前调用
beforeMount() {},
// 在绑定元素的父组件,以及他自己的所有子节点都挂载完成后调用
mounted() {},
// 绑定元素的父组件更新前调用
beforeUpdate() {},
// 在绑定元素的父组件,以及他自己的所有子节点都更新后调用
updated() {},
// 绑定元素的父组件卸载前调用
beforeUnmount() {},
// 绑定元素的父组件卸载后调用
unmounted() {}
}
}
这些钩子函数都接受同样的参数:
el
:指令绑定的元素的DOM。binding
:一个传参对象,包含以下的属性:value
:传递给指令的值。例如:v-focus="1"
,获取到的值就是 1oldValue
:更新之前的值,仅在beforeUpdate
和updated
中可用。无论值是否更改,它都可用。arg
:传递给指令的参数 (如果有的话)。例如在v-my-directive:foo
中,参数是"foo"
。modifiers
:传入修饰符的对象 。例如在v-my-directive.foo.bar
中,修饰符对象是{ foo: true, bar: true }
。instance
:使用该指令的组件实例。dir
:指令的定义对象。
vnode
:代表绑定元素的底层 VNode。prevNode
:之前的渲染中代表指令所绑定元素的 VNode。仅在beforeUpdate
和updated
钩子中可用。
举个例子,像下面这样使用指令:
<div v-example:foo.bar="baz">
binding
参数会是一个这样的对象:
{
arg: 'foo',
modifiers: { bar: true },//传递的修饰符
value: /* `baz` 的值 */,
oldValue: /* 上一次更新时 `baz` 的值 */
}
3.简化使用 mounted
和 updated
对于自定义指令来说,需要在
mounted
和updated
上实现相同的行为、又并不关心其他钩子的情况很常见。例如下面的例子:
app.directive("focus", {
mounted(el: HTMLInputElement, bing: DirectiveBinding) {
if (bing.value) {
el.focus();
}
},
updated(el: HTMLInputElement, bing: DirectiveBinding) {
if (bing.value) {
el.focus();
}
},
});
定义了一个自动聚焦input的指令,在组件挂载完成后,和组件更新后都去聚焦input元素。
可以简写成下面的例子:
app.directive("focus", (el: HTMLInputElement, bing: DirectiveBinding) => {
if (bing.value) {
el.focus();
}
});
不再传入一个配置对象,而是传入一个函数,这个函数会在组件的mounted
和updated
周期都执行。
4. 指定传入值的类型
在定义指令得时候,可以通过泛型来指定传入值的类型。
定义传入值的类型:
app.directive("focus", (el: HTMLInputElement, bing: DirectiveBinding<Person>) => {
el.focus();
console.log(bing.value.name);
});
使用:
<script setup lang="ts">
const reactive1 = reactive<Person>({
age: 0,
name: "tom"
});
</script>
<input v-focus="reactive1">
参数DirectiveBinding
指定泛型,指定的泛型就是传入的值的泛型。
5. 在组件上使用
当指令在组件上使用的时候,会因为组件的
透传特征
,流入并作用在组件内的根节点元素上。但是如果组件有多个根节点元素,那么指令就会被忽略不起作用,并抛出一个警告。不同于其他的透传属性,指令不能通过
v-bind="$attrs"
来指定绑定给某个元素,因此不推荐在组件上使用。
关于Vue3中的透传,可以阅读这篇文章:一文搞懂Vue3中的透传属性 - 掘金 (juejin.cn)