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
需求完成!

版权声明: (https://www.thinkmoon.cn/post/910)
本文首发于指尖魔法屋-Vue自定义指令
转载或引用必须申明原指尖魔法屋来源及源地址!