上一個篇章提到了基本的元件使用,雖然說是比較基礎的部分,但前前後後也寫了超過四千字的廢話。對於 Vue 比較熟悉的人來說,應該不會有什麼障礙才對。我們今天將會繼續提及,關於元件使用上的一些進階應用,也會接續上一篇比較沒有著墨的部分。


關於混合 Mixins

上一篇有約略提到 Mixins 的個特性,有曾經寫過 SCSS/SASS 的人應該對於這個東西不陌生。是的,他有點類似,也是將一些共用的函數提出去的一種作法。

實際上,Mixins 很類似一個元件的結構,只是他是被封裝成一個物件( Object ),然後透過元件的 mixins 屬性來導入。而 Mixins 本身有兩種作法,一種是寫給元件用,一種是可以註冊到 Vue 根元件上,也就是所謂的 全域 的概念。

// 這樣會定義一個全域的混合物件,大家都會套用。
Vue.mixin({
 created: function () {
   this.hello = 'world'
 }
})

// 這樣只單純宣告一個混合物件,誰要用誰就將他引入。
let myMixin = {
  created: function () {
   this.hello = 'world'
  }
}

然而,在 Vue 所提供的 Mixins 中,如果是數值的部分,會幫你把他合併,換句話說,如果你有一個 data (),然後你所使用的 Mixins 當中也有一個 data (),那麼,兩者所回傳的物件會被合併,當然,你必須要留意覆蓋問題。

<script>
let myMixin = {
  data: function () {
   return {
     foo: 'bar'
   }
  }
}

export default {
  name: 'MyComponent',
  mixins: [myMixin],
  data () {
    return {
      boo: 'bar'
    }
  }
}
</script>

上述的狀況,你的 data () 就會自動合併,

倘若你的元件中,有使用到跟 Mixins 一樣的數值,那麼你元件的優先權是 永遠大於 Mixins 裡面的設定的,換句話說,Mixins 裡面相同的設定會被 覆蓋掉 。是的,即便是 computed 或是 methods 的設定,全部都會被元件本身 同名 的設定覆蓋掉,這一點在使用上需要留意。

另外,如果是與生命週期有關的函數,那麼 Mixins 的優先權則反過來,會 永遠大於 元件裡面生命週期函數。換句話說,你的函數執行,會優先執行 Mixins 的部分,接著再執行元件裡面的函數。

那麼,使用 Mixins 可以帶來什麼好處?

  1. D.R.Y.
  2. 增加元件可重用性。
  3. 可抽離核心程式碼與邏輯區塊。

壞處呢?

  1. 程式碼分離後不好維護。
  2. 程式碼分離後不好維護。
  3. 程式碼分離後不好維護。

對的,就是因為代碼分離,而且其實他沒有任何有效的機制可以管理。所以,這個部分僅能透過團隊自主規範,或是溝通協作的部分來維持。


Directive 指令

接著我們來談元件中自定義指令的部分。

Custom Directive

我相信有寫過 Angular 的人對於 Directive 這件事情應該不陌生。是的,在 Vue 裡面,你在元件屬性上接上的諸如 v-bind 這一類的動作,就是內建的指令。然而這些指令,可以透過 Vue.directive() 或是元件內部的 directives 的方式來定義。兩者差異只是在一個是 全域 的,而一個只會作用在元件內部。

Vue.directive(
  'focus',
  {
    inserted: function (el) {
      el.focus()
    }
  }
)

/* OR */

export default {
  name: 'MyComponent',
  directives: {
    focus: {
      inserted (el) {
        el.focus()
      }
    }
  }
}

以照上述的例子,你在元件上面就會有一個叫做 v-focus 的指令可以使用。


指令本身有幾種勾子( Hook )可以使用:

  • bind 只會執行一次,在指令第一次被綁定到元件上時執行。
  • inserted 當元件被加入父元件時執行,可保證父元件存在,但不保證元件已經進入父元件節點中。
  • update 當元件更新時會呼叫此函數,但不能保證該元件其下的子元件都已更新。
  • componentUpdated 當元件與其下的子元件都已更新完畢後,呼叫此函數。
  • unbind 只會執行一次,在指令從元件被移除後執行。

而以上這幾種勾子,其所傳入的參數有:

  • el 當前元件的 DOM 節點。
  • binding 返回一個物件對象,內容包含了:
    • name 指令名稱,會去除掉 v- 的前綴。
    • value 指令綁定的回傳值。
    • oldValue 上一次的回傳值,僅適用於 updatecomponentUpdated
    • expression 指令綁定的回傳值,以字串形式回傳。
    • arg 指令的後綴關鍵字,例如 v-focus:boo 會回傳 boo
    • modifiers 指令的後綴修飾字,例如 v-focus:boo.a 會回傳 { a: true }
  • vnode Vue 所產生的虛擬節點。
  • oldVnode 上一個虛擬節點,僅適用於 updatecomponentUpdated

另外,指令後面的關鍵字是可以動態分配的,例如:

<div v-show-ads:[scrollPosition]="200"></div>

這樣來說我們就可以定義哪一些 scrollPosition 等於 200 的時候,要做什麼事情,或是該下怎麼樣的設定爾等。


過濾器 Filters

最後我們來聊聊過濾器這個東西,當然不是什麼 BRITA 之類的東西。自定義的過濾器只能在在元件內部,或是全域,且是在宣告 Vue 應用程式之前就先做好,不然基本上過濾器是無效的。

Vue.filter(
  'upperCase',
  function (value) {
    return value.toUpperCase()
  }
)

/* OR */

export default {
  name: 'MyComponent',
  filters: {
    upperCase (value) {
      return value.toUpperCase()
    }
  }
}

過濾器本身的應用範圍有兩個,一個是 {{ }} 雙引號變數內,另外一個是可以在 v-bind 後面的變數值使用。

<template>
  <section>
    <h1>{{ hello | upperCase }}</h1>
    <h2 v-bind:id="world | upperCase"></h2>
  </section>
</template>

大概就是這樣,然後你可以串接一堆的過濾器來做事。

<template>
  <section>
    <h1>{{ hello | upperCase | lowerCase | upperCase }}</h1>
  </section>
</template>

上面這個例子舉的比較不好。然後,由於過濾器本身就是 JavaScript 的函式,所以說,你也可以傳參數進去,

<template>
  <section>
    <h1>{{ hello | upperCase('arg1', arg2) }}</h1>
  </section>
</template>

以上述的例子來說,你傳入給 upperCase () 的參數就會有三個,

  1. hello 這個變數是第一個。
  2. arg1 這會是第二個。
  3. arg2 這是第三個,依此類推。

小結

元件多數可以使用的部分,在這個章節已經交代的差不多了。比較進階的部分我們會在接下來的章節中陸續提到。當然也會給出相當的範例讓大家比較容易理解。

ITHome 鐵人賽同步刊登 Component 進階應用 Day 3