Vue内部封装好的指令是内置指令,如v-if、v-model等,方便我们对dom元素完成某项操作。而自定义指令就是根据自身要求,自己编写且封装好的一些指令,有较高的灵活性。不过自定义指令也需要以v-开头。本文主要重点学习一下Vue3中自定义指令如何使用?
主要应用场景: 防抖、图片懒加载、一键 Copy的功能、拖拽、页面水印、权限校验、输入框自动聚焦、相对时间转换、下拉菜单
在Vue中,使用一个组件我们需要先注册再调用,简单点就是先声明再调用。自定义指令也是如此。组件可以注册为全局组件和局部组件,同理自定义指令也可以分为全局注册和局部注册。
使用自定义指令:
<template>
<input type="text" v-focus />
template>
全局注册自定义指令时,该自定义指令可以在任一组件上调用,代码复用率得到提高。
示例代码:
// main.js
import { createApp } from "vue";
import App from "./App.vue";
// 创建根节点
const app = createApp(App);
app.directive("focus", {
created(el, binding, vnode, prevVnode) {},
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) {},
});
// 挂载渲染根节点
app.mount("#app");
在上述代码中,可以借助Vue提供的directive方法来全局注册自定义指令。directive方法接收两个参数:指令名称和指令钩子函数对象。
批量注册指令:
// focus.js
export default const vCopy = { // 钩子函数
}
...
// directives/index.js
import copy from './copy'
import longpress from './longpress'
// 自定义指令
const directives = {
copy,
longpress,
}
export default {
// install方法是传入一个组件实例。
install(Vue) {
// 遍历自定义指令并使用Vue的directive方法全局注册指令
Object.keys(directives).forEach((key) => {
Vue.directive(key, directives[key])
})
}
}
// main.js
import { createApp } from "vue";
import App from "./App.vue";
import Directives from './directives'
const app = createApp(App);
Vue.use(Directives)
全局注册自定义指令是因为该自定义指令要作用于多个不同组件,但在某些特定情况下自定义指令只作用于一个组件,此时局部注册该指令更为合适。
<template>
</template>
<script setup>
const vFocus = {
created(el, binding, vnode, prevVnode) {},
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) {},
}
</script>
在Vue3中,以小写字母v开头的驼峰命名的变量都可以作为一个自定义指令使用,比如上段代码中vFocus就可以在模板中通过v-focus的指令形式使用。
在Vue3中,自定义指令中的钩子函数几乎和组件的生命周期钩子函数一样,这也是和Vue2中自定义指令的重大区别之一。
从上述代码可以知道,在Vue3中,自定义指令的钩子函数分别为:
钩子函数 | 执行时机 |
---|---|
created | 在绑定元素的 attribute 前或事件监听器应用前调用。 |
beforeMount | 在元素被插入到 DOM 前调用。 |
mounted | 在绑定元素的父组件及他自己的所有子节点都挂载完成后调用。 |
beforeUpdate | 绑定元素的父组件更新前调用。 |
updated | 在绑定元素的父组件及他自己的所有子节点都更新后调用。 |
beforeUnmount | 绑定元素的父组件卸载前调用。 |
unmounted | 绑定元素的父组件卸载后调用。 |
Vue2与Vue3中,钩子函数的参数不变,包括 el, binding, vnode, prevVnode
属性 | 含义 |
---|---|
value | 传递给指令的值。例如在 v-my-directive=“1 + 1” 中,值是 2。 |
oldValue | 之前的值,仅在 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 钩子中可用。
Vue3中,自定义提供了很多的钩子函数,但是实际开发中不需要使用这么多钩子函数。所以与Vue2相同,Vue3提供了自定义指令的简写形式。
示例代码:
<template>
<img alt="Vue logo" src="./assets/logo.png" />
<div v-focus="'#ccc'">
<input type="text" />
<div>{{ message }}div>
div>
<button @click="changeMsg">修改messagebutton>
template>
<script setup>
import { DirectiveBinding, ref } from "vue";
let message = ref<string>("小猪课堂");
const changeMsg = () => {
message.value = "张三";
};
// 在模板中启用 v-focus
const vFocus = (el: HTMLElement, binding: DirectiveBinding) => {
// 这会在 `mounted` 和 `updated` 时都调用
el.style.backgroundColor = binding.value;
};
script>
上段代码中我们省去了自定义指令中的所有钩子函数,直接简写为了一个箭头函数,该函数在 mounted 和 updated 时都调用。我们在div上绑定了自定义指令,并且传入了一个颜色参数。
后面的文章主要是学习 自定义指令的案例。