自定义指令
vue 默认内置了一些指令,如v-model 、v-bind 和 v-show 等,Vue 也允许注册自定义指令。
自定义指令可以提供很好的帮助:
- 组件权限验证
- 文本复制
- 快捷键绑定
- 滚动至指定位置
- 图片懒加载
- 焦点
指令钩子
指令是具有一组生命周期的钩子
ts
import type { Directive, DirectiveBinding } from 'vue'
const myDirective: Directive = {
// 在绑定元素的 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) {},
}一个指令定义对象可以提供如下几个钩子函数 (均为可选):
beforeMount:当指令第一次绑定到元素并且在挂载父组件之前调用。在这里你可以做一次性的初始化设置。mounted:在挂载绑定元素的父组件时调用。beforeUpdate:在更新包含组件的 VNode 之前调用。updated:在包含组件的 VNode 及其子组件的 VNode 更新后调用。beforeUnmount:在卸载绑定元素的父组件之前调用unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次。
函数简写
在很多时候,你可能想在 mounted 和 updated 时触发相同行为,而不关心其它的钩子。比如这样写:
ts
import type { Directive } from 'vue'
export const accessDirective: Directive = (el, binding) => {
const { hasAccess } = useAccess()
if (!hasAccess(binding.value))
el.parentNode?.removeChild(el)
}el:指令绑定到的元素。这可用于直接操作 DOM。
binding:包含以下 property 的对象。
instance:使用指令的组件实例。value:传递给指令的值。例如,在v-my-directive="1 + 1"中,该值为 2。oldValue:先前的值,仅在beforeUpdate和updated中可用。值是否已更改都可用。arg:参数传递给指令 (如果有)。例如在 v-my-directive:foo 中,arg 为 "foo"。modifiers:包含修饰符 (如果有) 的对象。例如在v-my-directive.foo.bar中,修饰符对象为{foo: true,bar: true}。dir:一个对象,在注册指令时作为参数传递。例如,在以下指令中vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
html
<div v-demo:foo.a.b="message"></div>
<input v-model:title.capitalize="myText" />ts
app.directive('demo', (el, binding, vnode) => {
})注册指令
ts
import type { Directive } from 'vue'
const app = Vue.createApp({})
const accessDirective: Directive = (el, binding) => {
const { hasAccess } = useAccess()
if (!hasAccess(binding.value))
el.parentNode?.removeChild(el)
}
// 注册一个全局自定义指令 `v-access`
app.directive('access', accessDirective)