Vue之自定義指令


先了解一下,在 vue 中,有很多內置的指令.

比如:

  • v-for 用於遍歷
  • v-if & v-show 用於隱藏和顯示元素(區別在於后者是修改 display:block|none,前者是不創建把元素從dom中刪除或者創建.
  • v-bind: 屬性綁定,把數據綁定在HTML元素的屬性上.
  • v-html & v-text 把數據綁定在HTML元素的屬性上,作用同 innerHTML & innerText
  • v-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元素,在這里就是后面那個有 placeholderinput
    • el 就等價於 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)

update()與conponentUpdated()幾乎是伴隨觸發,先觸發update()函數,再觸發componentUpdated()函數
  • 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=abc
    • oldValue 前一個值,只能在 update & componentUpdate 中使用.
    • expression : v-gqs='1+1',如果是 value = 2 ,如果是 expression = 1 + 1
    • arg: 指令傳遞的參數 ,比如 v-gqs:hello arg = hello
    • modifiers : 比如 v-gqs.a.b modifiers = {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}

 

 

 

 


免責聲明!

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



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