寫在文本前:相信在做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指令大致也就說這么多吧,如果錯誤,歡迎指正拍磚......