vue3自定义指令

383 阅读4分钟

一、什么是指令?

在vue中提供了一些对于页面 + 数据的更为方便的输出,这些操作就叫做指令, 以v-xxx表示
类似于html页面中的属性 <div v-xxx ></div>

二、指令的作用

指令中封装了一些DOM行为, 结合属性作为一个暗号, 暗号有对应的值,根据不同的值,框架会进行相关DOM操作的绑定

三、vue中常用的指令

  • v-text 元素的InnerText属性,必须是双标签
  • v-html 元素的innerHTML
  • v-if 判断是否插入这个元素
  • v-else-if
  • v-else
  • v-show 隐藏元素 如果确定要隐藏, 会给元素的style加上display:none
  • v-model 对于输入框实现数据的双向绑定
  • ......

四、自定义指令中传递的三个参数

  • el: 指令所绑定的元素,可以用来直接操作DOM。
  • binding: 一个对象,包含指令的很多信息。
  • vnode: Vue编译生成的虚拟节点。

五、自定义指令的生命周期

自定义指令有五个生命周期(也叫钩子函数),分别是 bind,inserted,update,componentUpdated,unbind

  • bind:只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个绑定时执行一次的初始化动作。
  • inserted:被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于document中)。
  • update:被绑定于元素所在的模板更新时调用,而无论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。
  • componentUpdated:被绑定元素所在模板完成一次更新周期时调用。
  • unbind:只调用一次,指令与元素解绑时调用。
//被绑定
bind:()=>{
    console.log('1 - bind');
},

//绑定到节点
inserted:()=>{
    console.log('2 - inserted');
},

//组件更新
update:()=>{
    console.log('3 - update');
},

//组件更新完成
componentUpdated:()=>{
    console.log('4 - componentUpdated');
},

//解绑
unbind:()=>{
    console.log('5 - bind');
}

六、vue3 自定义指令的变化

el: 指令绑定的元素,可以用来直接操作DOM

binding: 数据对象,包含以下属性:

  • 1.instance: 当前组件的实例,一般推荐指令和组件无关,如果有需要使用组件上下文ViewModel,可以从这里获取

  • 2.value: 指令的值。

  • 3.oldValue: 指令的前一个值,在beforeUpdate和Updated 中,可以和value是相同的内容。

  • 4.arg: 传给指令的参数,例如v-on:click中的click。

  • 5.modifiers: 包含修饰符的对象。例如v-on.stop:click 可以获取到一个{stop:true}的对象

vnode: Vue 编译生成的虚拟节点

prevVNode: Update时的上一个虚拟节点

Vue 3中钩子函数的生命周期和组件的生命周期类似:

  • created - 元素创建后,但是属性和事件还没有生效时调用。

  • beforeMount- 仅调用一次,当指令第一次绑定元素的时候。

  • mounted- 元素被插入父元素时调用.

  • beforeUpdate: 在元素自己更新之前调用

  • updated - 元素或者子元素更新之后调用.

  • beforeUnmount: 元素卸载前调用.

  • unmounted -当指令卸载后调用,仅调用一次

七、 全局自定义指令及局部自定义指令用法

全局自定义指令的写法:

  • 下面为全局自定义指令,也可引入vue自行封装js,此处方便演示,以main.js为例
  • 在使用自定义属性时,可以传入一个参数,并且在 binding 中的 value 属性可以调用到该值;
//main.js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
let app = createApp(App);
app.use(store).use(router).mount("#app");
// 改变背景色
app.directive("Highlight", {
  beforeMount(el, binding, vnode) {
    el.style.background = binding.value;
  },
});
  • 全局指令使用时在标签上写入v-指令名="'属性值'",没有属性值时等号及后面内容可以省略,即直接在标签写v-指令名
  • 属性值可以是变量,更多用法,可自行扩展
//页面使用
<template>
  <div class="box">
    <div class="a" style="width: 100px;height: 100px;" v-Highlight="'pink'"></div>
  </div>
</template>
<script setup>
import { ref, reactive, toRefs, watch, computed, defineProps, } from 'vue';
import { useStore } from 'vuex';
import { useRoute, useRouter } from 'vue-router';
const route = useRoute()
const router = useRouter()
const store = useStore()
const data = reactive({

})
</script>
<style scoped lang="scss"></style>

局部自定义指令的写法:

  • 示例:定义自定义指令,通过指令的生命周期控制元素;
  • 自定义指令使用小驼峰命名,在使用时用-分割;
  • 在使用自定义属性时,可以传入一个参数,并且在 binding 中的 value 属性可以调用到该值;
  • 注意:组合式API定义局部自定义指令时必须以小写v开头,必须以小驼峰命名,否则无法使用
驼峰式命名示例
  • 示例名称 tuofengmingming
  • 小驼峰 tuoFengMingMing
  • 大驼峰 TuoFengMingMing
组合式
<template>
  <div class="box">
    <input type="text" v-focus-automatic>
    <div v-color-red="'red'">测试内容</div>
  </div>
</template>
<script setup>
import { ref, reactive, toRefs, watch, computed, defineProps, } from 'vue';
import { useStore } from 'vuex';
import { useRoute, useRouter } from 'vue-router';
const route = useRoute()
const router = useRouter()
const store = useStore()
const data = reactive({

})
// const { } = toRefs(data)
// 输入框自动获焦
const vFocusAutomatic = {
  mounted: (el) => {
    el.focus()
  }
}
// 当前字体颜色
const vColorRed = {
  beforeMount: (el, binding, vnode) => {
    el.style.color = binding.value
  }
}
</script>
<style scoped lang="scss"></style>
选项式
<template>
  <input v-focus />
</template>
<script>
export default{
  setup() {},
  directives: {
    // 指令名
    focus: {
      // 生命周期
      mounted(el) {
        // 处理DOM的逻辑
        el.focus();
      },
    }
  }
}
</script>