Skip to content

自定义指令

基本使用

一个自定义指令由一个 包含类似组件生命周期钩子的对象 来定义。指令钩子函数会接收到指令所绑定元素作为其参数。

命名规范

自定义指令在 <script setup> 中以 v 开头的驼峰式命名,但在 <template> 模板中习惯以 -中划线方式命名。

vue
<template>
  <div v-highlight="isHighlight">这是被高亮的语句1</div>

  <div v-highlight="true">这是被高亮的语句2</div>
</template>

<script setup lang="ts">
  import { ref, type DirectiveBinding } from "vue"

  const isHighlight = ref<boolean>(true)

  const vHighlight = {
    mounted: (el: HTMLElement, binding: DirectiveBinding) => {
      // 严格校验 binding.value 的值,防止类型错误
      if (typeof binding.value !== "boolean") {
        console.warn("[Vue Warning]: The value of the custom directive 'vHighlight' must be of type boolean.")
        return
      }

      if (binding.value) {
        el.classList.add("is-highlight")
      }
    }
  }
</script>

<style scoped>
  .is-highlight {
    color: red;
  }
</style>
vue
<template>
  <div v-highlight="isHighlight">这是被高亮的语句1</div>

  <div v-highlight="true">这是被高亮的语句2</div>
</template>

<script lang="ts">
  import { ref, type DirectiveBinding } from "vue"

  export default {
    setup() {
      const isHighlight = ref<boolean>(false)
      return {
        isHighlight
      }
    },
    directives: {
      highlight: {
        mounted: (el: HTMLElement, binding: DirectiveBinding) => {
          if (typeof binding.value !== "boolean") {
            console.warn(
              "[Vue Warning]: The value of the custom directive 'vHighlight' must be of type boolean."
            )
            return
          }

          if (binding.value) {
            el.classList.add("is-highlight")
          }
        }
      }
    }
  }
</script>

<style scoped>
  .is-highlight {
    color: red;
  }
</style>

或者可以将 自定义指令 全局注册到应用层级:

ts
const app = createApp(App)

// 全局注册自定义指令
app.directive("highlight", {
  mounted: (el: HTMLElement, binding: DirectiveBinding) => {
    if (typeof binding.value !== "boolean") {
      console.warn(
        "[Vue Warning]: The value of the custom directive 'vHighlight' must be of type boolean."
      )
      return
    }

    if (binding.value) {
      el.classList.add("is-highlight")
    }
  }
})

app.mount("#app")

对象字面量

如果你的指令需要多个值,你可以向它传递一个 JavaScript 对象字面量。

vue
<template>
  <div v-highlight="{ color: 'red', backgroundColor: 'green' }">
    这是被高亮的语句2
  </div>
</template>

<script setup lang="ts">
  import { type DirectiveBinding } from "vue"

  const vHighlight = {
    mounted: (el: HTMLElement, binding: DirectiveBinding) => {
      // 心思缜密一些,typeof null 也是 object
      if (typeof binding.value !== "object" && binding.value !== null) {
        console.warn(
          "[Vue Warning]: The value of the custom directive 'vHighlight' must be of type object."
        )
        return
      }

      if (binding.value) {
        el.style.color = binding.value?.color
        el.style.backgroundColor = binding.value?.backgroundColor
      }
    }
  }
</script>

Released under the MIT License.