如何自己写一个vue自定义loading指令

2,128 阅读3分钟

手把手教你写一个vue自定义loading指令

昨天猛然发现 vue自定义指令 挺好玩的,可以实现很多效果,话不多,咱们开始吧, 2020.4.27更新:发现一个bug存在,当页面有好多个axios请求是,每次请求都会触发componentUpdated这个方法,就会导致页面出现好多个加载框。

使用背景

官网介绍说:有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。其实我觉得吧,用于页面展示的情况会比较多,只有你想不到,没有它做不到。

先来个小demo

// 注册一个全局自定义指令 `v-mydirective`
Vue.directive('mydirective', {
  bind: function (el) {
    // 可以进行一些逻辑操作
    console.log(el)
  }
})

//写好这个js后在main.js中引用,然后在页面上绑定一个元素

钩子函数

bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。

componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

unbind:只调用一次,指令与元素解绑时调用。

参数

关于参数,常用的有三个,

el:指令所绑定的元素,可以用来直接操作 DOM ,如果你要操作input的值,那么你需要el.addEventListener('input',(e)=>{  el.value = '12';})

binding:一个对象,包含以下属性:
  name:指令名,不包括 v- 前缀。
  value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
  oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
  expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
  arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
  modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
  
vnode:Vue 编译生成的虚拟节点。它包含有些你所绑定元素的属性。

ps:这些概念性的东西来源于vue的 官方文档,哈哈哈

到这里就差不多介绍完了vue的自定义指令,下面开始我们的主题,自己写一个loading指令

/**
 *    其实写这个指令挺简单的,要绑定一个boolean的值,当它为true的时候就往HTML代码里插入一个div,
 *然后在这个div里写好加载*样式,当它的值为false时,就把这个div给删除掉
 */
let oldValue = null
Vue.directive('myload', {
  // 当被绑定的元素插入到 DOM 中时……
  4.21更新:
  
  bind: function (el,binding) {
    oldValue = binding.value
    if (binding.value) {
        //始终设置只有一个加载中弹窗
        let myLoadBg = document.getElementById("my-load-bg");
        if (myLoadBg) {
          myLoadBg.parentNode.removeChild(myLoadBg)
        }
        let div = document.createElement("div");
        div.setAttribute("id", "my-load-bg");
        div.innerHTML = "<div class='load-box'>加载中</div>";//你也可以去网上找一些酷炫的加载效果放进去,哈哈哈
        document.body.appendChild(div);
    }else{
      let myLoadBg = document.getElementById("my-load-bg");
      myLoadBg.parentNode.removeChild(myLoadBg)
    }
  },
  componentUpdated(el, binding){
    if(oldValue != binding.value){
        if (binding.value) {
            //始终设置只有一个加载中弹窗
            let myLoadBg = document.getElementById("my-load-bg");
            if (myLoadBg) {
              myLoadBg.parentNode.removeChild(myLoadBg)
            }
          let div = document.createElement("div");
            div.setAttribute("id", "my-load-bg");
            div.innerHTML = "<div class='load-box'>加载中</div>";
            document.body.appendChild(div);
        }else{
          let myLoadBg = document.getElementById("my-load-bg");
          myLoadBg.parentNode.removeChild(myLoadBg)
        }
    }
  }
})

然后在main.js里引入

在页面上用的时候 v-myload="true/false"就可以啦,


第一次写这么长文章,可能写的不太好,嘿嘿