除了 Vue 内置的一系列指令 (比如 v-model 或 v-show) 之外,Vue 还允许你注册自定义的指令 (Custom
Directives)。
自定义指令主要是为了重用涉及普通元素的底层 DOM 访问的逻辑。
一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。
举例:
在某个场景下,需要一进入页面或者打开某个弹窗就聚焦到指定的输入框。
局部的写法:
<script setup>
const vFocus = {
created(el, binding, vnode) {
},
beforeMount(el, binding, vnode) {
},
mounted(el) {
el.focus()
},
beforeUpdate(a,b,c,prevNode) { //! 第四个参数 prevNode 只在beforeUpdate和updated才有!
},
updated() {},
beforeUnmount() {
// 当指令绑定的元素 的父组件销毁前调用。 <简单讲,指令元素的父组件销毁前调用>
},
unmounted() {},// 当指令与元素解除绑定且父组件已销毁时调用。
}
</script>
<template>
<input v-focus>
</template>
全局的写法:
import { createApp } from 'vue'
const app = createApp(App)
app.directive('focus',{
created(el, binding, vnode) {
},
beforeMount(el, binding, vnode) {
},
mounted() {
el.focus()
},
beforeUpdate(a,b,c,prevNode) { //! 第四个参数 prevNode 只在beforeUpdate和updated才有!
},
updated() {},
beforeUnmount() {
// 当指令绑定的元素 的父组件销毁前调用。 <简单讲,指令元素的父组件销毁前调用>
},
unmounted() {},// 当指令与元素解除绑定且父组件已销毁时调用。
})
我门可以发现对比vue2来看vue3里自定义指令似乎在生命周期这块发生了某些变化,下面我们来看看具体的。
注意:后面的示例都用局部的自定义指令来讲解。
vue2自定义指令生命周期
vue3自定义组件生命周期
这些生命周期都会接受以下几个参数:
el, binding, vnode, prevVnode
他们分别代表什么意思呢?
el:指令绑定到的元素。这可以用于直接操作 DOM。
binding:一个对象,包含以下属性。
vnode:代表绑定元素的底层 VNode。
prevNode:之前的渲染中代表指令所绑定元素的 VNode。仅在 beforeUpdate 和 updated 钩子中可用。
这样看可能抽象了点,我们在指令的mounted里打印下这4个参数,可见:
<script setup>
const vFocus = {
created(el, binding, vnode) {
},
beforeMount(el, binding, vnode) {
},
mounted(el,binding, vnode,prevVnode) {
console.log('el--',el)
console.log('binding-',binding)
console.log('vnode-',vnode)
console.log('prevVnode-',prevVnode)
console.log()
el.focus()
},
beforeUpdate(a,b,c,prevNode) { //! 第四个参数 prevNode 只在beforeUpdate和updated才有!
},
updated() {},
beforeUnmount() {
// 当指令绑定的元素 的父组件销毁前调用。 <简单讲,指令元素的父组件销毁前调用>
},
unmounted() {},// 当指令与元素解除绑定且父组件已销毁时调用。
}
</script>
我们主要看el和binding。
我们通过自定义指令来画一个固定宽高和背景色的方块吧!
//name:自定义参数,hqg:自定义修饰符
<div v-myDirective:name.hqg="{background: '#ccc', width: '200px', height: '200px'}">
这是一个div
</div>
const vMyDirective = {
mounted(el,binding, vnode,prevVnode) {
console.log('binding',binding)
el.style.background = binding.value.background
el.style.width = binding.value.width
el.style.height = binding.value.height
},
}
只有当所需功能只能通过直接的 DOM 操作来实现时,才应该使用自定义指令。其他情况下应该尽可能地使用 v-bind 这样的内置指令来声明式地使用模板,这样更高效,也对服务端渲染更友好。