Vue3$View-CustomDirectives
0. Custom Directives in Big Picture
指令是用来操作 DOM 的。Vue 提供的内置指令可以完成大部分功能,但有时我们也需要自定义指令。
一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。
<script setup>
const vFocus = {
mounted: (el) => el.focus()
}
</script>
<template>
<input v-focus />
</template>
const app = createApp({})
// 全局 v-focus
app.directive('focus', {
/* ... */
})
1. 组件的定义
Directive Hooks
const myDirective = {
// called before bound element's attributes
// or event listeners are applied
created(el, binding, vnode, prevVnode) {
// see below for details on arguments
},
// called right before the element is inserted into the DOM.
beforeMount(el, binding, vnode, prevVnode) {},
// called when the bound element's parent component
// and all its children are mounted.
mounted(el, binding, vnode, prevVnode) {},
// called before the parent component is updated
beforeUpdate(el, binding, vnode, prevVnode) {},
// called after the parent component and
// all of its children have updated
updated(el, binding, vnode, prevVnode) {},
// called before the parent component is unmounted
beforeUnmount(el, binding, vnode, prevVnode) {},
// called when the parent component is unmounted
unmounted(el, binding, vnode, prevVnode) {}
}
参数
el:指令绑定到的元素。(可读可写)binding:对象,包含以下属性value:传递给指令的值。oldValue:之前的值,仅在beforeUpdate和updated中可用。arg:传递给指令的参数modifiers:一个包含修饰符的对象 (如果有的话)。例如在v-my-directive.foo.bar中,修饰符对象是{ foo: true, bar: true }。instance:使用该指令的组件实例。dir:指令的定义对象。
vnode:代表绑定元素的底层 VNode。prevVnode:代表之前的渲染中指令所绑定元素的 VNode。仅在beforeUpdate和updated钩子中可用。
函数简写
mounted 和 updated时
app.directive('color', (el, binding) => {
// this will be called for both `mounted` and `updated`
el.style.color = binding.value
})
2. 使用
在组件上使用
不推荐。只能用在单根元素组件上。
防止重复提交
// 1. 设置 v-throttle 自定义指令
app.directive('throttle', {
mounted(el, binding) {
let throttleTime = binding.value; // 节流时间
if (!throttleTime) {
throttleTime = 2000;
}
let cbFun;
el.addEventListener('click', event => {
// 第一次点击:执行&设置时间
if (!cbFun) {
cbFun = setTimeout(() => {
cbFun = null;
}, throttleTime);
// 时间内点击:不允许
} else {
event && event.stopImmediatePropagation();
}
}, true);
},
});
// 2. 使用
<button @click="sayHello" v-throttle>提交</button>