什么是指令?
指令是控制视图的一种集成方式,可以直接对 DOM 进行操作,例如 Vue 内置的指令v-if
、v-show
和v-for
等等。
指令在 Vue 中属于底层行为,是一种数据绑定机制的产物。自定义指令是给开发者提供的一种接口,是可以操作 DOM 的,但是 Vue 不建议我们直接操作 DOM,但是某些情况下,又不得不进行操作。
例如我们想要实现一个自定义的指令v-my-show
,我们首先要做的是注册自定义指令,这和注册 component 是一样的,都可以通过局部或全局进行注册:
// 局部注册
import myShow from "./directives/index";
export default {
name: "App",
directives: {
myShow
}
};
// 全局注册
import myShow from "./directives/index";
createApp(App)
.directive("my-show", myShow)
.mount("#app");
以上两种方式,我们选择一种进行注册即可!
注册指令后,我们通过v-指令名称
使用:
<div class="box box1" v-my-show="visible1"></div>
<button @click="visible1 = !visible1">Show/Hide</button>
指令构造函数
指令和组件一样,同样存在生命钩子函数,在某些时候执行:
const myDirective = {
// 在绑定元素的 attribute 前或事件监听器应用前调用
created(el, binding, vnode, prevVnode) {},
// 在元素被插入到 DOM 前调用
beforeMount(el, binding, vnode, prevVnode) {},
// 在绑定元素的父组件及他自己的所有子节点都挂载完成后调用
mounted(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件更新前调用
beforeUpdate(el, binding, vnode, prevVnode) {},
// 在绑定元素的父组件及他自己的所有子节点都更新后调用
updated(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件卸载前调用
beforeUnmount(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件卸载后调用
unmounted(el, binding, vnode, prevVnode) {}
}
export default myDirective;
可以看到以上以上 7 个钩子函数都有 4 个参数,下面对这些参数进行解释:
- el:被绑定指令的元素,是一个 DOM 元素;
- bindings:
- arg: 指令的参数,例如
v-my-show:abc
中abc
就是参数; - dir: 当前指令对象内的所有属性,也就是以上 7 个钩子函数;
- instance: 使用当前指令的组件实例,可以获取到组件实例中的一些数据;
- modifiers: 自定义指令的修饰符集合,例如
v-my-show.test
中.test
就是修饰符; - oldValue: 更新之前指令的值,钩子函数
beforeUpdate
、updated
才会存在该值; - value: 当前指令绑定的值,例如
v-my-show="visible1"
中visible1
就是指令的值;
- arg: 指令的参数,例如
- vNode:绑定指令元素的虚拟节点;
- prevNode: 上一个虚拟节点,钩子函数
beforeUpdate
、updated
才会存在该值;
对于自定义指令来说,一个很常见的情况是仅仅需要在mounted
和updated
上实现相同的行为,除此之外并不需要其他钩子。这种情况下我们可以直接用一个函数来定义指令,如下所示:
export default function(el, binding, vNode, prevNode){
// 其他操作
}
在组件上使用
当在组件上使用自定义指令时,它会始终应用于组件的根节点,和透传 attributes 类似。
<MyComponent v-demo="test" />
<!-- v-demo 指令会被应用在此处 -->
<div>
<span>My component content</span>
</div>
需要注意的是组件可能含有多个根节点。当应用到一个多根组件时,指令将会被忽略且抛出一个警告。和 attribute 不同,指令不能通过 v-bind=”$attrs” 来传递给一个不同的元素。总的来说,不推荐在组件上使用自定义指令。