vue3的自定义指令详解

vue3的自定义指令详解

  • 一、认识自定义指令
  • 二、指令的生命周期
  • 三、指令的参数和修饰符
  • 四、自定义指令练习

一、认识自定义指令

在Vue的模板语法中我们学习过各种各样的指令:v-show、v-for、v-model等等,除了使用这些指令之外,Vue也允许我们来自定义自己的指令
  • 注意:在Vue中,代码的复用和抽象主要还是通过组件
  • 通常在某些情况下,你需要对DOM元素进行底层操作,这个时候就会用到自定义指令

自定义指令分为两种

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

比如我们来做一个非常简单的案例:当某个元素挂载完成后可以自定获取焦点

  • 实现方式一:如果我们使用默认的实现方式
<template>
  <div>
    <input type="text" ref="input" />
  </div>
</template>

<script>
import { ref, onMounted } from "vue";

export default {
  setup () {
    const input = ref(null);

    onMounted(() => {
      input.value.focus();
    })

    return {
      input
    }
  }
}
</script>

<style scoped>
</style>
  • 实现方式二:自定义一个 v-focus 的局部指令
<template>
  <div>
    <input type="text" v-focus>
  </div>
</template>

<script>
  export default {
    // 局部指令
    directives: {
      focus: {
        mounted(el, bindings, vnode, preVnode) {
          console.log("focus mounted");
          el.focus();
        }
      }
    }
  }
</script>

<style scoped>

</style>
  • 实现方式三:自定义一个 v-focus 的全局指令
 app.directive("focus", {
   mounted(el, bindings, vnode, preVnode) {
     console.log("focus mounted");
     el.focus();
   }
 })

二、指令的生命周期

一个指令定义的对象,Vue提供了如下的几个钩子函数

  • created:在绑定元素的 attribute 或事件监听器被应用之前调用;
  • beforeMount:当指令第一次绑定到元素并且在挂载父组件之前调用;
  • mounted:在绑定元素的父组件被挂载后调用;
  • beforeUpdate:在更新包含组件的 VNode 之前调用;
  • updated:在包含组件的 VNode 及其子组件的 VNode 更新后调用;
  • beforeUnmount:在卸载绑定元素的父组件之前调用;
  • unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次;
<template>
  <div>
    <button v-if="counter < 2" v-why @click="increment">当前计数: {{counter}}</button>
  </div>
</template>

<script>
  import { ref } from "vue";

  export default {
    // 局部指令
    directives: {
      why: {
        created(el, bindings, vnode, preVnode) {
          console.log("why created", el, bindings, vnode, preVnode);
          console.log(bindings.value);
          console.log(bindings.modifiers);
        },
        beforeMount() {
          console.log("why beforeMount");
        },
        mounted() {
          console.log("why mounted");
        },
        beforeUpdate() {
          console.log("why beforeUpdate");
        },
        updated() {
          console.log("why updated");
        },
        beforeUnmount() {
          console.log("why beforeUnmount");
        },
        unmounted() {
          console.log("why unmounted");
        }
      }
    },
    setup() {
      const counter = ref(0);
      const increment = () => counter.value++;

      return {
        counter,
        increment
      }
    }
  }
</script>

<style scoped>

</style>

三、指令的参数和修饰符

  • 如果我们指令需要接受一些参数或者修饰符应该如何操作呢?
  • info是参数的名称
  • aaa-bbb是修饰符的名称
  • 后面是传入的具体的值
  • 在我们的生命周期中,我们可以通过 bindings 获取到对应的内容
    在这里插入图片描述
    vue3的自定义指令详解_第1张图片

四、自定义指令练习

  • 自定义指令案例:时间戳的显示需求
  • 在开发中,大多数情况下从服务器获取到的都是时间戳
  • 我们需要将时间戳转换成具体格式化的时间来展示
  • Vue2中我们可以通过过滤器来完成
  • 在Vue3中我们可以通过计算属性(computed) 或者 自定义一个方法(methods) 来完成
  • 其实我们还可以通过一个自定义的指令来完成
  • 我们来实现一个可以自动对时间格式化的指令v-format-time
  • 这里我们封装了一个函数,在首页中我们只需要调用这个函数并且传入app即可

目录结构
vue3的自定义指令详解_第2张图片
format-time.js

import dayjs from 'dayjs';

export default function(app) {
  app.directive("format-time", {
    created(el, bindings) {
      bindings.formatString = "YYYY-MM-DD HH:mm:ss";
      if (bindings.value) {
        bindings.formatString = bindings.value;
      }
    },
    mounted(el, bindings) {
      const textContent = el.textContent;
      let timestamp = parseInt(textContent);
      if (textContent.length === 10) {
        timestamp = timestamp * 1000
      }
      el.textContent = dayjs(timestamp).format(bindings.formatString);
    }
  })
}

index.js

import registerFormatTime from './format-time';

export default function registerDirectives(app) {
  registerFormatTime(app);
}

App.vue

<template>
  <h2 v-format-time="'YYYY/MM/DD'">{{timestamp}}</h2>

  <h2 v-format-time>{{timestamp}}</h2>
  <h2 v-format-time>{{timestamp}}</h2>
  <h2 v-format-time>{{timestamp}}</h2>
  <h2 v-format-time>{{timestamp}}</h2>
  <h2 v-format-time>{{timestamp}}</h2>

</template>

<script>
  export default {
    setup() {
      const timestamp = 1624452193;

      return {
        timestamp
      }
    },
    mounted() {
      console.log("app mounted");
    }
  }
</script>

<style scoped>

</style>

main.js

import { createApp } from 'vue'
import App from './03_自定义指令/App.vue'
import registerDirectives from './directives'

const app = createApp(App);

registerDirectives(app);

app.mount('#app');

你可能感兴趣的:(Vue日常总结,前端,vue.js,javascript)