Vue3的自定义指令基础使用笔记

103 阅读3分钟

vue的模版语法是系统自带的指令(比如v-modlev-show),除了这些指令之外我们还可以自定义指令Vue常用的代码复用方式:组件组合式函数。组件主要用于构建木块,组合式函数祖尧用于复用逻辑。自定义指令可以说是第三种代码复用的方式,它主要是为了复用涉及普通元素的底层Dome访问逻辑。在开发组件库的时候常用到自定义指令。

自定义指令分类:

自定义指令可以分成两类:自定义局部指令自定义全局指令。自定义指令由directives(一个类似于生命周期钩子的对象)来构建的

  • 自定义局部指令:组件中通过directives选项,只能在当前组建中使用;
  • 自定义全局指令:app的directive方法,可以在任意组建中被使用。

基础使用

举个例子:

下面代码在页面中有一个input框,进入该页面时会立即获取input的焦点:

 <template>
     <div>
         <input type="text" ref="input">
     </div>
 </template>
 ​
 <script>
 import {onMounted, ref} from "vue"
 export default {
     setup () {
         const input = ref(null)
         onMounted(()=>{
             // focus自动获取焦点
             input.value.focus()
         })
         return {
             input
         }
     }
 }
 </script>
 ​
 <style scoped>
 ​
 </style>
 ​

如果想要将这段代码复用,我们除了使用hook的方式将这段代码抽取出来之外,还可以采用自定义指令的方式:

 <template>
     <div>
       <input type="text" v-focus/>
     </div>
   </template>
   
   <script>
   export default {
     directives:{
       focus: {
         mounted(el){
             el.focus()
         }
       }
     },
     setup() {
       return {
       };
     },
   };
   </script>
   
   <style scoped></style>

上面代码在进入页面之后input也会自动聚焦,在<script setup>中,任何以v开头的驼峰命名的变量都可以被当作一个自定义指令使用,如下例子:

 <template>
   <div>
     <input type="text" v-focus />
   </div>
 </template>
 ​
 <script setup>
 const vFocus = {
   mounted: (el) => el.focus(),
 };
 </script>
 ​
 <style scoped></style>

以上都是自定义局部指令,如果是要自定义全局指令的话需要拿到createApp()返回的app对象,使用directive注册全局指令。一般Vue项目都会在main.js中注册:

 import { createApp } from "vue";
 import App from "./06_自定义指令/App";
 ​
 const app = createApp(App)
 app.directive('focus',{
     mounted(el){
         el.focus()
     }
 })
 app.mount("#app")

注:在学习全局注册自定义指令是我犯过一个小错误,在vscode中这段代码并不会报错,查看浏览器终端会发现:Uncaught TypeError: app.directive is not a function。这是因为mount()方法并不会返回app实例,所以需要吧createApp(App).mount("#app")拆分成两部份,如我上面正确例子中的代码。错误示例如下:

 import { createApp } from "vue";
 import App from "./06_自定义指令/App";
 ​
 const app = createApp(App).mount("#app")
 app.directive('focus',{
     mounted(el){
         el.focus()
     }
 })

指令的生命周期钩子

自定义指令也提供了一些可选的生命周期钩子,下面是官方文档示例:

 const myDirective = {
   // 在绑定元素的 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) {}
 }

钩子参数

钩子函数都会接受四个参数:elbindingvnodeprevVnode

  • el:返回一个指令绑定的DOM,可以直接通过el操作这个DOM对象;
  • binding:这是一个对象,里面包含了一些指令传递的信息,这个在官方文档中描述的非常详尽,建议大家直接去看官方文档;
  • vnode:表示虚拟节点VNode,不了解虚拟节点的可以去看一下Vue的虚拟DOM原理;
  • prevVNode:表示之前渲染的虚拟VNode。

以上仅是vue自定义指令的基础使用,跟多的使用方式(例如:简写形式、对象字面量)请去看官方文档。

另外在最后给大家推荐一个社区,DEV社区,里面有很多技术大佬,很多Vue生态的问题都能够在里面得到解答。

参考资料:

vue3官方文档