【Vue3从零开始-第五章】5-2 自定义指令

590 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第27天,点击查看活动详情

前言

上一篇的文章中,我们了解了vue高级语法中的mixin语法,本章节中将会和大家一起学习vue里面的自定义指令的内容。

前菜

在vue里面比如想要操作DOM,可以通过ref属性去定义,然后通过$refs获取到DOM元素从而实现操作DOM。

比如想要做一个输入框自动聚焦的功能,就可以在input标签中定义ref属性,然后在mounted生命周期函数中使用$refs操作input标签。

<script>
  const app = Vue.createApp({
    mounted(){
      this.$refs.input.focus()
    },
    template: `
      <div>
        <input ref='input' />
      </div>
    `
  });

  const vm = app.mount('#root');

</script>

chrome-capture.gif

刷新页面之后,input标签就会自动获取焦点了。但是通过ref操作DOM元素在一些简单的需求中比较好用,但是它不能被复用,其实如果想要操作DOM,还可以通过自定义指令directive的方式去实现。

directive

全局指令

<script>
  const app = Vue.createApp({
    template: `
      <div>
        <input v-focus />
      </div>
    `
  });

  app.directive('focus', {
    mounted(el){
      el.focus()
    }
  })

  const vm = app.mount('#root');

</script>
  • 全局的directive方法和定义组件一样,也是通过app定义的。

  • directive方法中的第一个参数是自定义指令的名称,在标签中可以通过v-指令名称的方式使用自定义指令。

  • directive方法中的第二个参数是一个对象,里面可以写当前指令的生命周期函数。

  • 在生命周期中会接收一个el参数,这个参数可以用来操作DOM元素。

局部指令

const directives = {
    focus: {
      mounted(el){
        el.focus()
      }
    }
  }

const app = Vue.createApp({
    directives: directives,
    template: `
      <div>
        <input v-focus />
      </div>
    `
});
  • 局部的自定义指令方式和局部组件的定义方式差不多,都是在app实例上面自定义一个对象。

  • 自定义的对象里面会有一个指令名称的对象,指令名称里面也是当前自定义指令对应的生命周期函数。

  • 组件实例中通过directives引用局部自定义指令。

  • 标签上还是通过v-指令名称的方式使用自定义指令。

生命周期

自定义指令的生命周期和vue组件实例的生命周期是一样的,其中的区别就是:

  • 组件实例的beforeMountmounted是组件挂载到vue上面的时候触发的。
  • 自定义指令的beforeMountmounted是指令挂载到标签上面的时候触发的。
  • 自定义指令的生命周期函数中会接收参数,从而操作DOM。

自定义指令的生命周期函数:beforeMountmountedbeforeUpdateupdatedbeforeUnmoutunmounted

<script>
  const app = Vue.createApp({
    data(){
      return {
        show: true
      }
    },
    template: `
      <div v-if="show">
        <input v-focus />
      </div>
    `
  });

  app.directive('focus', {
    beforeMount(el){
      console.log('focus beforeMount')
    },
    mounted(el){
      console.log('focus mounted')
    },
    beforeUpdate(el){
      console.log('focus beforeUpdate')
    },
    updated(el){
      console.log('focus updated')
    },
    beforeUnmount(el){
      console.log('focus beforeUnmount')
    },
    unmounted(el){
      console.log('focus unmounted')
    }
  })

  const vm = app.mount('#root');

</script>

Kapture 2022-04-27 at 22.48.15.gif

通过v-if指令去判断DOM是否被销毁,然后在浏览器控制台中改变show的值,就会输出beforeUnmountunmounted生命周期函数中的内容。

🐔大家可以试试用v-show指令,看看会执行哪些生命周期函数。

传值

上面用到的v-if指令,亦或是以前学到的v-showv-model指令都会赋值,那我们自定义指令也想要赋值,并且在指令生命周期函数中使用该怎么做呢?

🌰 小例子:比如想要通过自定义指令给一个DOM元素距顶部的距离

<script>
  const app = Vue.createApp({
    template: `
      <div v-pos="100" style="position: absolute;">
        Hello World
      </div>
    `
  });

  app.directive('pos', {
    mounted(el, binding){
      el.style.top = binding.value + 'px'
    }
  })

  const vm = app.mount('#root');

</script>

image.png

  • 自定义指令的mounted生命周期函数中额外接收了一个参数binding,这个参数里面有一个value就是自定义指令中传递过来的值。
  • 通过el参数操作DOM元素,然后拿到binding中的value值,就可以实现自定义指令传值了。

当然我们也可以把自定义指令的值改为动态的,这样也会方便修改。

const app = Vue.createApp({
    data(){
      return {
        top: 110
      }
    },
    template: `
      <div v-pos="top" style="position: absolute;">
        Hello World
      </div>
    `
});

Kapture 2022-04-27 at 23.05.32.gif

当我们在浏览器控制台修改top的值时,发现DOM元素上的样式并没有修改,那这时候就可以用到自定义指令的另外一个生命周期函数updated

app.directive('pos', {
    mounted(el, binding){
      el.style.top = binding.value + 'px'
    },
    updated(el, binding){
      el.style.top = binding.value + 'px'
    }
})

Kapture 2022-04-27 at 23.09.38.gif

其实mountedupdated生命周期函数中的内容是一样的,那么就可以使用一种简写的方式。

app.directive('pos', (el, binding) => {
    el.style.top = binding.value + 'px'
})
  • directive函数中第二个参数改为一个函数,同样接收elbinding两个参数,这样就可以同时实现mountedupdated生命周期函数了。

绑定属性

以前的内容中,我们可以通过v-bind:属性名亦或者v-on:事件名的方式绑定一些自定义的名称,那么在自定义指令里面是不是也可以绑定自定义属性呢?

<script>
  const app = Vue.createApp({
    template: `
      <div v-pos:right="100" style="position: absolute;">
        Hello World
      </div>
    `
  });

  app.directive('pos', (el, binding) => {
    console.log('binding:', binding)
    el.style.top = binding.value + 'px'
  })

  const vm = app.mount('#root');

</script>

image.png

directive函数中打印了binding的值,会看到里面有一个arg就是我们在DOM元素中通过自定义指令绑定的属性,而value就是自定义指令后面传递的值。

那么我们就可以通过binding.arg的方式去使用自定义指令绑定的属性。

app.directive('pos', (el, binding) => {
    el.style[binding.arg] = binding.value + 'px'
})

image.png

总结

本章节主要讲解了自定义指令directive,它也分为全局和局部,类似于组件的定义方式。还讲解了自定义指令传值、绑定属性的方式,希望大家多写写代码熟悉它的使用方法。大家一起加油!!💪🏻