directive
vue官方提供了v-if,v-model等指令方便大家快捷开发,还提供了供开发者自己diy的自定义指令directive
自定义指令中有几个钩子
- created:在绑定元素的属性前,或者事件监听器应用前调用
- beforeMount:在元素被插入到DOM前调用,例如我们想要实现输入框的自动聚焦,就不能在beforeMount钩子中实现
- mounted:在绑定元素的父组件以及自己的所有子节点都挂载完毕后调用,这个时候DOM已经渲染出来,我们实现输入框自动聚焦也是在这个钩子函数中实现
- beforeUpdate:绑定元素的父组件更新前调用
- updated:在绑定元素的父组件以及自己的所有子节点都更新完毕后调用
- beforeUnmount:绑定元素的父组件卸载前调用
- unmounted:绑定元素的父组件卸载后调用
也可以不用对象,简写成一个函数下面的实例简写为一个函数
钩子里的参数
-
el:指令绑定到的DOM元素,可以用于直接操作当前元素,默认传入钩子的就是el参数,例如我们开始实现的focus指令,就是直接操作的元素DOM -
binding:这是一个对象,包含以下属性:value:在元素上使用指令时,传递给指令的值。oldValue:之前的值,一般用于beforeUpate和updated钩子函数中,例如:beforeUpdate(el, {oldValue: ''})arg:传递给指令的参数,非必需,例如<div v-reverse:foo="'hello'"></div>,那么传递给指令的参数就是foomodifiers:一个由修饰符构成的对象,例如<div v-reverse.foo.bar="'hello'"></div>,那么该修饰符对象为{foo: true, bar: true},我们经常使用到的事件修饰符,其实和这个差不多。instance:使用该指令的组件实例,注意不是DOMdir:指令的定义对象
-
vnode:绑定元素的地城VNode -
preVnode:之前的渲染中代表指令所绑定的元素的VNode,一般用于beforeUpate和updated钩子函数中
自定义指令分为2中,私有的和全局的
私有自定义指令
在vue3中有一个快捷方法就是V开头的函数,驼峰命名就可以默认
<template>
<div v-red>这是a</div>
</template>
<script setup>
const vRed = (el) => {
el.style.color = 'red';
};
</script>
或者在组件内祖册
<template>
<div v-red>这是a</div>
</template>
<script>
export default {
directives: {
red: (el) => {
el.style.color = 'red';
}
}
};
</script>
效果:
全局自定义指令
自动聚焦例子:在src下新建directive文件夹,focus.js文件 默认导出
export default (el) => {
el.focus()
};
在main.js引入
import focus from '@/directive/focus';
在组件中使用
createApp(App).directive('focus', focus).mount('#app');
开发中常见的自定义指令
防抖
mounted(el, binding) {
// 至少需要回调函数以及监听事件类型
if (typeof binding.value.fn !== 'function' || !binding.value.event) return;
let delay = 200; // 默认延迟时间
el.timer = null;
el.handler = function () {
if (el.timer) {
clearTimeout(el.timer);
el.timer = null;
}
el.timer = setTimeout(() => {
binding.value.fn.apply(this, arguments);
el.timer = null;
}, binding.value.delay || delay);
};
el.addEventListener(binding.value.event, el.handler);
},
// 元素卸载前也记得清理定时器并且移除监听事件
beforeMount(el, binding) {
if (el.timer) {
clearTimeout(el.timer);
el.timer = null;
}
el.removeEventListener(binding.value.event, el.handler);
}
<button v-debounce="{ fn: handleClick, event: 'click', delay: 500 }">
权限按钮
function isRole(value) {
let queryButtonList = ['a', 'b', 'c', 'd'];
return queryButtonList.some((item) => item == value);
}
export default (el, binding) => {
el.parentNode.removeChild(el);
};
一键复制
const copy = {
mounted(el, { value }) {
el.$value = value
el.handler = () => {
if (!el.$value) {
console.log('无复制内容')
return
}
const textarea = document.createElement('textarea')
textarea.readOnly = 'readonly'
textarea.style.position = 'absolute'
textarea.style.left = '-9999px'
textarea.value = el.$value
document.body.appendChild(textarea)
textarea.select()
const result = document.execCommand('Copy')
if (result) {
console.log('复制成功') // 可根据项目UI仔细设计
}
document.body.removeChild(textarea)
}
el.addEventListener('click', el.handler)
},
updated(el, { value }) {
el.$value = value
},
beforeMount(el) {
el.removeEventListener('click', el.handler)
},
}
export default copy