Vue自定义指令

介绍

Vue中的指令形如v-*,如v-if,v-show,v-model等。同时,除了Vue自带的一些默认指令外,Vue同时运行用户自定义指令,来扩展指令功能。

使用场景

究竟什么情况下使用组件?而什么情况下使用指令呢?官方对此,给出了以下建议:

注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。

也就是说,当你关注问题的抽象层级在DOM元素的时候,你就应该考虑使用自定义指令来完成需求了。

作用范围

自定义指令有两种作用范围,一种是申明在全局,全局内有效。另一种,则是局部指令。

钩子函数及相关参数见官网文档。

举个例子

需求

我需要设计一个自定义指令v-bug,该指令可将作用元素的所有内容都替换为烫烫烫烫,指令可以指定有几个烫,以及是否追加锟斤拷

1. 先将内容替换为一个

main.js


import Vue from 'vue'

import App from './App.vue'



Vue.config.productionTip = false



Vue.directive('bug', {

  inserted: function (el) {

    el.innerHTML = "烫"

  }

})



new Vue({

  render: h => h(App),

}).$mount('#app')

App.vue


<template>

  <div id="app">

    <HelloWorld v-bug />

  </div>

</template>



<script>

import HelloWorld from './components/HelloWorld.vue'



export default {

  name: 'App',

  components: {

    HelloWorld

  }

}

</script>



<style>

#app {

  font-family: Avenir, Helvetica, Arial, sans-serif;

  -webkit-font-smoothing: antialiased;

  -moz-osx-font-smoothing: grayscale;

  text-align: center;

  color: #2c3e50;

  margin-top: 60px;

}

</style>

效果展示

2020-09-20T05:28:47.png

2. 生成指定个数的

main.js


...

Vue.directive('bug', {

  inserted: function (el, binding) {

    el.innerHTML = Array(binding.value).fill("烫").join("")

  }

})

...

App.vue


<template>

  <div id="app">

    <HelloWorld v-bug="12" />

  </div>

</template>

2020-09-20T05:29:25.png

3. 指定是否追加锟斤拷

main.js


...

Vue.directive('bug', {

  inserted: function (el, binding) {

    let html = Array(binding.value).fill("烫").join("")

    if(binding.modifiers.suffix){

      html += "锟斤拷"

    }

    el.innerHTML = html

  }

})

...

App.vue


<template>

  <div id="app">

    <HelloWorld v-bug.suffix="12" />

  </div>

</template>

2020-09-20T05:30:18.png

但是此时的代码有个非常严重的问题,从上文代码中可看出,内容的改变只在inserted的时候执行。如果我们将指令后面设置为变量,变量值的改变却不会影响到个数(这一点都不Vue),所有我们应再监听一下指令的updated钩子函数。

4. 数据驱动(动态改变)

App.vue


<script>

import HelloWorld from "./components/HelloWorld.vue";



let interval = null

export default {

    name: "App",

    components: {

        HelloWorld

    },

    data() {

        return {

            num: 12

        };

    },

    created() {

        interval = setInterval(() => {

            this.num++;

        }, 1000);

    },

    beforeDestroy(){

      clearInterval(interval)

    }

};

</script>

main.js


...

function generateHtml(binding){

  let html = Array(binding.value).fill("烫").join("")

  if (binding.modifiers.suffix) {

    html += "锟斤拷"

  }

  return html

}

Vue.directive('bug', {

  inserted: function (el, binding) {

    el.innerHTML = generateHtml(binding)

  },

  update: function (el, binding) {

    if (binding.oldValue !== binding.value) {

      el.innerHTML = generateHtml(binding)

    }

  },

})

...

2020-09-11T14:22:08.png

需求完成!

版权声明: 本文首发于 指尖魔法屋-Vue自定义指令(https://blog.thinkmoon.cn/post/910_vue%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4/) 转载或引用必须申明原指尖魔法屋来源及源地址!