持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
前言
学习vue3有一段时间了,也用vue3写了几个项目,今天抽空整理一下关于vue3的自定义指令知识,写文章的初衷是,加深自己的记忆、理解,方便以后复习、查阅。
内置指令与自定义指令
vue本身内置了一系列的指令(如:v-model、v-if、v-show),除了这些内置指令以外,还允许自己注册指令,也就是自定义指令。
指令的作用主要也是复用代码,它与组件和组合式函数的不同是,指令主要处理的是涉及DOM元素访问的逻辑;而组件主要是代码模块化;组合式函数主要是侧重代码逻辑的封装。
自定义指令的使用方式
使用指令之前,都需要先注册,分全局注册和局部注册。
- 全局注册:在所有的页面都可以使用
// main.ts
const app = createApp()
app.directive('xxx', {})
// <div v-xxx></div> // 在页面中使用
- 局部注册:分两种,一种是使用Option API方式,另一种是使用Composition API,只在当前页面有效。 在option api中,其定义方式和vue2是完全一致的
// option api 和vue2一样
export default {
directives: {
xxx: {}
}
}
// <div v-xxx></div> // 在页面中使用
composition api ,在<script setup>中,任何以v开头的驼峰形式命名的变量,都可以用作指令。
// composition api
<script setup lang='ts'>
const vXxx = {/**/}
</script>
// <div v-xxx></div> // 在页面中使用
vue3自定义指令的变化
- 生命周期钩子:vue3的指令生命周期向组件靠拢,两者越发的像了,也更加的便于理解;看下具体的变化。
// vue3
const vXxx = {
// 在绑定元素的 attribute 前
// 或事件监听器应用前调用
created(el, binding, vnode, prevVnode) {},
// 在元素被插入到 DOM 前调用
beforeMount() {},
// 在绑定元素的父组件
// 及他自己的所有子节点都挂载完成后调用
mounted() {},
// 绑定元素的父组件更新前调用
beforeUpdate() {},
// 在绑定元素的父组件
// 及他自己的所有子节点都更新后调用
updated() {},
// 绑定元素的父组件卸载前调用
beforeUnmount() {},
// 绑定元素的父组件卸载后调用
unmounted() {}
}
// vue2
const vXxx2 = {
// 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
bind(el, binding, vnode, oldVnode) {},
// 被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
inserted() {},
// 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前
// 指令的值可能发生了改变,也可能没有。
// 但是你可以通过比较更新前后的值来忽略不必要的模板更新
update() {},
// 指令所在组件的 VNode 及其子 VNode 全部更新后调用。
componentUpdated() {},
// 只调用一次,指令与元素解绑时调用。
unbind() {},
}
通过上面的对比,就可以很清楚的看出来,vue3重写了指令的生命周期钩子,这更加的合理,使用起来和组件的差不多,减少心智负担。
- 钩子函数参数:vue3除了重写了生命周期钩子函数,还对函数参数做了一些小调整,主要是binding对象的更改。
- 去除了
name属性,表示指令名,不包括v-前缀。 - 去除了
expression属性,表示字符串形式的指令表达式。例如v-xxx="1 + 1"中,表达式为"1 + 1"。 - 新增
instance属性,表示使用该指令的组件实例 - 新增
dir属性,表示指令的定义对象
注意事项
vue3中因为支持一个template下面可以同时有多个根节点,所以,如果指令用在一个多根节点的组件中,指令会不生效,并且会抛出一个错误。