先了解一下,在 vue 中,有很多內置的指令.
比如:
v-for用於遍歷v-if&v-show用於隱藏和顯示元素(區別在於后者是修改display:block|none,前者是不創建把元素從dom中刪除或者創建.v-bind:屬性綁定,把數據綁定在HTML元素的屬性上.v-html&v-text把數據綁定在HTML元素的屬性上,作用同innerHTML&innerTextv-on:綁定HTML元素事件v-if&v-else-if&v-else條件渲染v-model綁定表單元素,實現雙向綁定.
等等.....
所以,關於指令,我們可以總結下面幾點:
- 指令是寫在 HTML 屬性地方的.
<input v-model='name' type='text' /> - 指令都是以
v-開頭的. - 指令表達式的右邊一般也可以跟值
v-if = false
2.0 Vue自定義指令場景小DEMO(非常尬)
場景: 我們需要一個指令,寫在某個HTML表單元素上,然后讓它在被加載到DOM中時,自動獲取焦點.
// 和自定義過濾器一樣,我們這里定義的是全局指令 Vue.directive('focus',{ inserted(el) { el.focus() } })
<div id='app'> <input type="text"> <input type="text" v-focus placeholder="我有v-focus,所以,我獲取了焦點"> </div>
這里放了兩個 input ,但是后面的 input 才使用了我們的自定義 v-focus 指令,所以看到了是后面那個文本框獲取了焦點,而不是前面一個.

先總結幾個點:
- 使用
Vue.directive()來新建一個全局指令,(指令使用在HTML元素屬性上的) Vue.directive('focus')第一個參數focus是指令名,指令名在聲明的時候,不需要加v-- 在使用指令的HTML元素上,
<input type="text" v-focus placeholder="我有v-focus,所以,我獲取了焦點"/>我們需要加上v-. Vue.directive('focus',{})第二個參數是一個對象,對象內部有個inserted()的函數,函數有el這個參數.el這個參數表示了綁定這個指令的DOM元素,在這里就是后面那個有placeholder的inputel就等價於document.getElementById('el.id')....- 可以利用
$(el)無縫連接jQuery
指令的生命周期
其實上面個例子很尬!
HTML5 本身就提供了一個 autofocus 的屬性,我們直接寫這個就OK了.
用指令我們需要:
- 新增一個指令
- 定義指令的第二個參數里的
inserted函數 - 在需要獲取焦點的元素上,使用這個指令.
非常的費時費力....
在說明,為什么我要這么麻煩的使用指令之前,可以先了解一下指令的一些基本知識.
上述例子中,我們寫了一個叫 inserted(){} 的函數,
有了 inserted 就說明了,指令在綁定到 HTML 元素上時,肯定也是有一堆鈎子函數的,說白了也就是生命周期.
當一個指令綁定到一個元素上時,其實指令的內部會有五個生命周期事件函數.
先上官方說明:
-
bind(){}當指令綁定到 HTML 元素上時觸發.只調用一次. -
inserted()當綁定了指令的這個HTML元素插入到父元素上時觸發(在這里父元素是div#app).但不保證,父元素已經插入了 DOM 文檔. -
updated()所在組件的VNode更新時調用. -
componentUpdate指令所在的組件的VNode以及其子VNode全部更新后調用. -
unbind: 指令和元素解綁的時候調用,只調用一次
Vue.directive('gqs',{ bind() { // 當指令綁定到 HTML 元素上時觸發.**只調用一次** console.log('bind triggerd') }, inserted() { // 當綁定了指令的這個HTML元素插入到父元素上時觸發(在這里父元素是 `div#app`)**.但不保證,父元素已經插入了 DOM 文檔.** console.log('inserted triggerd') }, update() { // 所在組件的`VNode`更新時調用. console.log('update triggerd') }, componentUpdated() { // 指令所在組件的 VNode 及其子 VNode 全部更新后調用。 console.log('componentUpdated triggerd') }, unbind() { // 只調用一次,指令與元素解綁時調用. console.log('unbind triggerd') } })
HTML
<div id='app' v-gqs></div>
結果
bind triggerd
inserted triggerd
發現默認情況下只有 bind 和 inserted 聲明周期函數觸發了.
那么剩下的三個什么時候觸發呢?
<div id='app' > <p v-gqs v-if="show">v-if是刪除或者新建dom元素,它會觸發unbind指令聲明周期嗎?</p> <button @click="show=!show">toggle</button> </div>
一開始猜測 unbind 應該是刪除元素的時候觸發,也是弄了個 v-if.
然后點擊按鈕,發現果然如此.
當指令綁定的元素被銷毀時,會觸發指令的 unbind 事件.
(新建並顯示,仍然是觸發 bind & inserted)
- v-show的顯示/隱藏
- :style與:class的樣式改變時(:style={fontSize:fontSize+'px'} :style={changeClass: bool} )
- 內容改變 (v-model="text") v-mode一定要綁定,否則無法觸發
注意:使用this.$refs.<dom>來修改隱藏、顯示、樣式、內容是無法觸發update()和componentUpdated()
利用指令,可以做一些小事情.
既然,指令並不是一次性的活.
當綁定指令的元素的狀態發生改變時(這里主要是指元素綁定的vue數據發生改變時),仍然會觸發指令中的 update 函數.
那么我們可以利用指令的簡寫形式,來做一些有意思的事情.
核心思想就是:
當一個HTML元素設置了指令,那么在這個元素的狀態發生改變時(由vue數據變化帶來的帶來的監控),我們可以利用update()鈎子函數監控到這個元素的變化,然后根據需要做一些其他的事情.
使用官方指定的指令簡寫模式:
Vue.directive('color-swatch', function (el, binding) { el.style.backgroundColor = binding.value })
inserted or update .
當元素的狀態發生改變時,就會觸發 update
在寫demo之前,還需要了解一下指令鈎子函數的幾個參數.
el: 綁定指令的那個dom元素.(doucument.getElementById('el.id')binding: 一個對象name:v-gqs==>gqs不包括前面的v-valule: 指令后面的值v-gqs='abc'value=abcoldValue前一個值,只能在update&componentUpdate中使用.expression:v-gqs='1+1',如果是value=2,如果是expression=1 + 1arg: 指令傳遞的參數 ,比如v-gqs:helloarg = hellomodifiers: 比如v-gqs.a.bmodifiers= {a:true,b:true}
vnode:Vue編譯生成的虛擬節點.oldVnode:上一個虛擬節點,僅在update&componentUpdated中可用.
Vue.directive('change-bgc', (el, binding,vnode,oldVnode) => { el.style.backgroundColor = 'red' console.log(`binding.name:${binding.name}`) console.log(`binding.value:${binding.value}`) console.log(`binding.expression:${binding.expression}`) console.log(`binding.arg:${binding.arg}`) console.log(`binding.modifiers:${JSON.stringify(binding.modifiers)}`) console.log(`binging.oldValue:${binding.oldValue}`) console.log(`vnode:${Object.keys(vnode).join(',')}`) console.log(`oldVnode:${JSON.stringify(oldVnode)}`) })
binding.name:change-bgc binding.value:2 binding.expression:1+1 binding.arg:foo binding.modifiers:{"left":true,"bottom":true} binging.oldValue:undefined vnode:tag,data,children,text,elm,ns,context,fnContext,fnOptions,fnScopeId,key,componentOptions,componentInstance,parent,raw,isStatic,isRootInsert,isComment,isCloned,isOnce,asyncFactory,asyncMeta,isAsyncPlaceholder oldVnode:{"tag":"","data":{},"children":[],"raw":false,"isStatic":false,"isRootInsert":true,"isComment":false,"isCloned":false,"isOnce":false,"isAsyncPlaceholder":false}
