vue.js自定義指令詳解


寫在文本前:相信在做vue的項目,你肯定接觸了指令,我們常用vue內置的一些指令,比如v-model,v-text,v-if,v-show等等,但是這些內置指令不在本文的講解范疇,本文想說的是其自定義指令。思考一下,自定義指令我們用在哪里?是不是一下子想不出來,感覺做一般的項目很少用到指令呢,想不到指令用在哪!!因為我們的確很少用,但不是說不會用。看官方api文檔里有這么一句話:普通 DOM 元素進行底層操作,這時候就會用到自定義指令。也就是說我們在操作普通DOM的時候有可能會用到。在做項目的時候,我們有很多種方法來替代自定義指令,所以讓我們忽略了vue自定義指令的用處。下邊我們一步步來了解vue自定義指令。

舉幾個栗子

(1、輸入框焦點自動觸發。
(1、輸入框的電話號碼,郵箱,身份證號碼等的校驗。

上面這幾個場合,我們在做項目的時候完全可以用其他方法代替,但是vue自定義指令能讓我們做到一勞永逸,做到一處定義,全局調用。使其代碼簡潔高效,維護方便。接下來,我們會一步步深入vue自定義指令。

1、首先看下官方介紹,如下:

/*  自定義指 */
import Vue from 'vue'
/**
 * 模板
 * v-lang
 * 五個注冊指令的鈎子函數
 */
Vue.directive('mydirective', {
  /**
   * 1.被綁定
   * 做綁定的准備工作
   * 比如添加事件監聽器,或是其他只需要執行一次的復雜操作
   */
  bind: function(el, binding, vnode) {
    console.log('1 - bind');
  },
  // 2.綁定到節點
  inserted: function(el, binding, vnode) {
    console.log('2 - inserted');
  },
  /**
   * 3.組件更新
   * 根據獲得的新值執行對應的更新
   * 對於初始值也會調用一次
   */
  update: function(el, binding, vnode, oldVnode) {
    console.log('3 - update');
  },
  // 4.組件更新完成
  componentUpdated: function(el, binding, vnode, oldVnode) {
    console.log('4 - componentUpdated');
  },
  /**
   * 5.解綁
   * 做清理操作
   * 比如移除bind時綁定的事件監聽器
   */
  unbind: function(el, binding, vnode) {
    console.log('5 - bind');
  }
})
/**
鈎子函數
1、bind:只調用一次,指令第一次綁定到元素時調用,用這個鈎子函數可以定義一個綁定時執行一次的初始化動作。
2、inserted:被綁定元素插入父節點時調用(父節點存在即可調用,不必存在於document中)。
3、update:被綁定於元素所在的模板更新時調用,而無論綁定值是否變化。通過比較更新前后的綁定值,可以忽略不必要的模板更新。
4、componentUpdated:被綁定元素所在模板完成一次更新周期時調用。
5、unbind:只調用一次,指令與元素解綁時調用。
*/

 

執行順序:
頁面加載時

bind
inserted

 

組件更新時

update
componentUpdated

 

卸載組件時

unbind

 

官方地址請移步至,directive,上面只是做了個簡單的說明,接下來我們詳細的介紹vue自定義指令的各個鈎子函數到底如何觸發。

2、鈎子函數簡單講解

就個人而言, bind和update也許是這五個里面最有用的兩個鈎子了.這個也是我們下邊主要要說的2個鈎子函數。其它函數不常用,我也沒搞明白。

(1)鈎子函數 bind

bind:只調用一次,指令第一次綁定到元素時調用。在這里可以進行一次性的初始化設置。

<input id="input1" v-mydirective> // html元素

Vue.directive('mydirective', {
  bind: function(el, binding, vnode) {
   el.style.border = "1px solid red"
  }
}

 

上面代碼的效果就是輸入框的邊框變成了1像素的紅色。當然你也可以設置其它試試。

<input id="input1" v-mydirective> // html元素

Vue.directive('mydirective', {
  bind: function(el, binding, vnode) {
    el.addEventListener('click', function (event) {
        alert('hellow world')
    })
  }
}

 

在bind鈎子函數里,我們可以添加一些事件,在其某種條件下觸發(比如點擊事件,鍵盤事件),如上代碼,點擊input輸入框就會彈出 “hellow world”。至於bind里面的參數的含義,建議自己動手輸入出來看看。很簡單是吧,下邊我們來些稍微復雜一點的。看如下代碼:

指令鈎子函數會被傳入以下參數:

/**
鈎子函數的參數:(el, binding, vnode, oldVnode)
el:指令所綁定的元素,可以用來直接操作 DOM 。
binding:一個對象,包含以下屬性
  name:指令名,不包含v-的前綴;
  value:指令的綁定值;例如:v-my-directive="1+1",value的值是2;
  oldValue:指令綁定的前一個值,僅在update和componentUpdated鈎子函數中可用,無論值是否改變都可用;
  expression:綁定值的字符串形式;例如:v-my-directive="1+1",expression的值是'1+1';
  arg:傳給指令的參數;例如:v-my-directive:foo,arg的值為 'foo';
  modifiers:一個包含修飾符的對象;例如:v-my-directive.a.b,modifiers的值為{'a':true,'b':true}
vnode:Vue編譯的生成虛擬節點;
oldVnode:上一次的虛擬節點,僅在update和componentUpdated鈎子函數中可用。
*/

 

這里我們着重注意一下,binding對象下的value,oldValue,arg,expression,modifiers這幾個屬性,根據這幾個屬性,我們可以做到更強大的自定義指令,下邊我們參考案例來說:

<div v-mydirective:left="100" id=”box"></div> // html元素

Vue.directive('mydirective', {
  bind: function(el, binding, vnode) {
       el.style.position = 'fixed';
       const s = (binding.arg === 'left' ? 'left' : 'top');
       el.style[s] = binding.value + 'px';
  }
}

 

上面的代碼是使id=”box“的這個div元素絕對定位了,而且設置了left的值為100px;

(2)鈎子函數 update

update:每當元素本身更新(但是子元素還未更新)時觸發。這句話怎么理解呢?我們用案例來說明,如下:

<template>
  <div id="box">
       <input v-model="myname" v-mydirective/>
  </div>
<template>
export default {
  data(){
    return{
      myname:"zhangshan"
    }
  },
  directives:{
    'mydirective':{
         update: function(el, binding, vnode, oldVnode) {
              console.log('update更新了');
         }
    }
  }
}

 

上邊代碼,輸入框默認值是"zhangshan",如果我們修改了myname值,那么就會觸發update函數的執行,輸出“update更新了”

再來個復雜一點的案例如下:

<template>
  <div id="box">
       <input type="text" v-model="myname"  v-mydirective="{type:'name',val:myname}"/>
       <input type="text" v-model="myemail"  v-mydirective="{type:'email',val:myemail}"/>
  </div>
<template>
export default {
  data(){
    return{
      myname:"zhangshan",
      myemail:'***@163.com'
    }
  },
  directives:{
    'mydirective':{
         update: function(el, binding, vnode, oldVnode) {
           //update:指令的值可能發生了改變,也可能沒有。但是你可以通過比較更新前后的值來忽略不必要的模板更新 
           if(binding.oldValue.val != binding.value.val){// 進行判斷,避免同時觸發多個判斷
             let checkStatus = true;// 定義驗證狀態 局部變量
             if(binding.value.type == 'name'){
                   if(binding.value.val.length>5){
                        checkStatus = false;
                        console.log("輸入的姓名長度大於5了")
                   }
             }
             if(binding.value.type == 'email'){// 驗證郵箱
               if(!/^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-   z0-9]+$/g.test(binding.value.val)){
                  checkStatus = false;
               }
             }
             if(checkStatus){
                el.style.border = "1px solid #333";//驗證通過input邊框顏色就變成#333
             }else{
                el.style.border = "1px solid red";//驗證不通過input邊框顏色就變成紅色
             }
         }
       }
    }
  }
}

 

上邊的案例,我們通過bind下的modifiers屬性實現。modifiers:一個包含修飾符的對象;例如:v-my-directive.a.b,modifiers的值為{'a':true,'b':true}。這樣我們在update鈎子函數里根據所傳入的type類型做判斷來執行哪個驗證方法。

(3)鈎子函數 inserted

inserted:被綁定元素插入父節點時調用(父節點存在即可調用,不必存在於document中)。

<input id="input1" v-mydirective> // html元素

Vue.directive('mydirective', {
  inserted: function(el, binding, vnode) {
    el.focus()//輸入框自動獲取焦點
  }
}

 

對於鈎子函數 inserted,我也是一知半解,所用的不多,但是有個常用的方法是寫在這里面的,就是輸入框自動獲取焦點,也就是上面的代碼。

(4)鈎子函數 bind和鈎子函數 inserted的區別。
據文檔所說,插入父節點時調用 inserted,來個測試。
bind: function (el) {
 console.log(el.parentNode) // null
 console.log('bind')
},
inserted: function (el) {
 console.log(el.parentNode) // <div id="login">...</div>這個元素是指令所在元素的父元素,具體根據自己的寫法不同
 console.log('inserted')
}

 

分別在兩個鈎子函數中輸出父節點:bind 時父節點為 null,inserted 時父節點存在。

(5)鈎子函數 componentUpdated和鈎子函數 unbind
 // 4.組件更新完成
  componentUpdated: function(el, binding, vnode, oldVnode) {
        console.log('4 - componentUpdated')
  },
   /*** 5.解綁
     * 做清理操作
     * 比如移除bind時綁定的事件監聽器
   */
    unbind: function(el, binding, vnode) {
       console.log('5 - bind');
    }

 

對於這2個鈎子函數,沒有做太多的研究,unbind可能會用到,用於釋放實例資源占用等操作。

關於vue.js指令大致也就說這么多吧,如果錯誤,歡迎指正拍磚......


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM