自訂指令


目錄

  • #簡介

  • 鉤子函數
    • 鉤子函數參數
    • 動態指令參數
  • 函數簡寫
  • 物件字面量


簡介

#除了核心功能預設內建的指令(v-model

v-show

),Vue 也允許註冊自訂指令。注意,在 Vue2.0 中,程式碼重複使用和抽象的主要形式是元件。然而,有的情況下,你仍然需要對普通 DOM 元素進行底層操作,這時候就會用到自訂指令。舉個聚焦輸入框的例子,如下:4.gif

當頁面載入時,該元素將獲得焦點(注意:

autofocus 在移動版Safari 上不工作)。事實上,只要你在打開這個頁面後還沒點擊過任何內容,這個輸入框就應該還是處於聚焦狀態。現在讓我們用指令來實現這個功能:

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})

如果想註冊局部指令,元件中也接受一個

directives 的選項:

directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus()
    }
  }
}

然後你可以在模板中任何元素上使用新的

v-focus
屬性,如下:

<input v-focus>

鉤子函數


    一個指令定義物件可以提供以下幾個鉤子函數(皆為可選):
  • bind
  • :只呼叫一次,指令第一次綁定到元素時呼叫。這裡可以進行一次性的初始化設定。

  • inserted
  • :被綁定元素插入父節點時呼叫 (僅保證父節點存在,但不一定已插入文件)。

    update

    :所在元件的 VNode 更新時調用,
  • 但可能發生在其子 VNode 更新之前
。指令的值可能發生了改變,也可能沒有。但你可以透過比較更新前後的值來忽略不必要的模板更新 (詳細的鉤子函數參數見下)。

我們會在稍後

討論###渲染函數###時介紹更多 VNodes 的細節。 ###
  • componentUpdated:指令所在元件的 VNode 及其子 VNode 全部更新後呼叫。

  • unbind:只呼叫一次,指令與元素解綁時呼叫。

接下來我們來看看鉤子函數的參數(即 elbindingvnode 和 oldVnode)。


鉤子函數參數


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

  • el:指令所綁定的元素,可以用來直接操作DOM 。

  • binding:一個對象,包含以下屬性:

    • name:指令名,不包括v- 前綴。

    • value:在指令的綁定值,例如:v-my-directive="1 1" 中,綁定值為2

    • oldValue:指令綁定的前一個值,僅在 updatecomponentUpdated 鉤子中可用。無論值是否改變都可用。

    • 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 編譯產生的虛擬節點。移步 VNode API 來了解更多詳情。

  • oldVnode:上一個虛擬節點,僅在 updatecomponentUpdated 鉤子中可用。

除了 el 之外,其它參數都應該是唯讀的,切勿進行修改。如果需要在鉤子之間共享數據,建議透過元素的 dataset 來進行。

這是一個使用了這些屬性的自訂鉤子範例:

<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
Vue.directive('demo', {
  bind: function (el, binding, vnode) {
    var s = JSON.stringify
    el.innerHTML =
      'name: '       + s(binding.name) + '<br>' +
      'value: '      + s(binding.value) + '<br>' +
      'expression: ' + s(binding.expression) + '<br>' +
      'argument: '   + s(binding.arg) + '<br>' +
      'modifiers: '  + s(binding.modifiers) + '<br>' +
      'vnode keys: ' + Object.keys(vnode).join(', ')
  }
})

new Vue({
  el: '#hook-arguments-example',
  data: {
    message: 'hello!'
  }
})

1.jpg


##動態指令參數

指令的參數可以是動態的。例如,在 v-mydirective:[argument]="value" 中,argument 參數可以根據元件實例資料進行更新!這使得自訂指令可以在應用中被靈活使用。

例如你想要建立一個自訂指令,用來透過固定佈局將元素固定在頁面上。我們可以像這樣建立一個透過指令值來更新垂直位置像素值的自訂指令:

<div id="baseexample">
  <p>Scroll down the page</p>
  <p v-pin="200">Stick me 200px from the top of the page</p>
</div>
Vue.directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    el.style.top = binding.value + 'px'
  }
})
new Vue({
  el: '#baseexample'
})

這會把該元素固定在距離頁面頂部 200 像素的位置。但如果場景是我們需要把元素固定在左側而不是頂部又該怎麼辦呢?這時使用動態參數就可以非常方便地根據每個元件實例來進行更新。

<div id="dynamicexample">
  <h3>Scroll down inside this section ↓</h3>
  <p v-pin:[direction]="200">I am pinned onto the page at 200px to the left.</p>
</div>
Vue.directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    var s = (binding.arg == 'left' ? 'left' : 'top')
    el.style[s] = binding.value + 'px'
  }
})
new Vue({
  el: '#dynamicexample',
  data: function () {
    return {
      direction: 'left'
    }
  }
})

結果:

1.gif

這樣這個自訂指令現在的彈性就足以支援一些不同的用例了。


函數簡寫


#在很多時候,你可能會想在bind update 時觸發相同行為,而不關心其它的鉤子。例如這樣寫:

Vue.directive('color-swatch', function (el, binding) {
  el.style.backgroundColor = binding.value
})


物件字面量


##如果指令需要多個值,可以傳入一個JavaScript 物件字面量。記住,指令函數能夠接受所有合法的 JavaScript 表達式。


<div v-demo="{ color: 'white', text: 'hello!' }"></div>
Vue.directive('demo', function (el, binding) {
  console.log(binding.value.color) // => "white"
  console.log(binding.value.text)  // => "hello!"
})