Vue可復用性和組合

混入

基礎(chǔ)

混入(mixins)是一種分發(fā)Vue組件中可復用功能的非常靈活的方式?;烊雽ο罂梢园我饨M件選項。當組件使用混入對象時,所有混入對象的選項將被混入該組件本身的選項。

// 定義一個混入對象
var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}
// 定義一個使用混入對象的組件
var Component = Vue.extend({
  mixins: [myMixin]
})
var component = new Component() // => "hello from mixin!"

選項合并

當組件和混入對象含有同名選項時,這些選項將以恰當?shù)姆绞交旌稀?br> 比如,數(shù)據(jù)對象在內(nèi)部會進行淺合并 (一層屬性深度),在和組件的數(shù)據(jù)發(fā)生沖突時以組件數(shù)據(jù)優(yōu)先。

var mixin = {
  data: function () {
    return {
      message: 'hello',
      foo: 'abc'
    }
  }
}
new Vue({
  mixins: [mixin],
  data: function () {
    return {
      message: 'goodbye',
      bar: 'def'
    }
  },
  created: function () {
    console.log(this.$data)
    // => { message: "goodbye", foo: "abc", bar: "def" }
  }
})

同名鉤子函數(shù)將混合為一個數(shù)組,因此都將被調(diào)用。另外,混入對象的鉤子將在組件自身鉤子之前調(diào)用。

var mixin = {
  created: function () {
    console.log('混入對象的鉤子被調(diào)用')
  }
}
new Vue({
  mixins: [mixin],
  created: function () {
    console.log('組件鉤子被調(diào)用')
  }
})
// => "混入對象的鉤子被調(diào)用"
// => "組件鉤子被調(diào)用"

值為對象的選項,例如methods,componentsdirectives,將被混合為同一個對象。兩個對象鍵名沖突時,取組件對象的鍵值對。

var mixin = {
  methods: {
    foo: function () {
      console.log('foo')
    },
    conflicting: function () {
      console.log('from mixin')
    }
  }
}
var vm = new Vue({
  mixins: [mixin],
  methods: {
    bar: function () {
      console.log('bar')
    },
    conflicting: function () {
      console.log('from self')
    }
  }
})
vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "from self"

注意:Vue.extend()也使用同樣的策略進行合并。

全局混入

也可以全局注冊混入對象。注意使用! 一旦使用全局混入對象,將會影響到所有之后創(chuàng)建的Vue實例。使用恰當時,可以為自定義對象注入處理邏輯。

// 為自定義的選項 'myOption' 注入一個處理器。
Vue.mixin({
  created: function () {
    var myOption = this.$options.myOption
    if (myOption) {
      console.log(myOption)
    }
  }
})
new Vue({
  myOption: 'hello!'
})
// => "hello!"

自定義選項合并策略

自定義選項將使用默認策略,即簡單地覆蓋已有值。如果想讓自定義選項以自定義邏輯合并,可以向Vue.config.optionMergeStrategies添加一個函數(shù):

Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {
 // return mergedVal
}

對于大多數(shù)對象選項,可以使用 methods 的合并策略:

var strategies = Vue.config.optionMergeStrategies
strategies.myOption = strategies.methods

自定義指令

當需要對普通DOM元素進行底層操作,這時候就會用到自定義指令。
舉個聚焦輸入框的例子。當頁面加載時,該元素將獲得焦點。事實上,只要你在打開這個頁面后還沒點擊過任何內(nèi)容,這個輸入框就應(yīng)當還是處于聚焦狀態(tài)。

// 注冊一個全局自定義指令 `v-focus`
Vue.directive('focus', {
  // 當被綁定的元素插入到 DOM 中時……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})

如果想注冊局部指令,組件中也接受一個directives的選項:

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

<input v-focus>

鉤子函數(shù)

一個指令定義對象可以提供如下幾個鉤子函數(shù) (均為可選):

  • bind:只調(diào)用一次,指令第一次綁定到元素時調(diào)用。在這里可以進行一次性的初始化設(shè)置。
  • inserted:被綁定元素插入父節(jié)點時調(diào)用 (僅保證父節(jié)點存在,但不一定已被插入文檔中)。
  • update:所在組件的VNode更新時調(diào)用,但是可能發(fā)生在其子 VNode 更新之前。指令的值可能發(fā)生了改變,也可能沒有。但是你可以通過比較更新前后的值來忽略不必要的模板更新。
  • componentUpdated:指令所在組件的VNode及其子VNode全部更新后調(diào)用。
  • unbind:只調(diào)用一次,指令與元素解綁時調(diào)用。

鉤子函數(shù)參數(shù)

指令鉤子函數(shù)會被傳入以下參數(shù):

  • el:指令所綁定的元素,可以用來直接操作DOM。
  • binding:一個對象,包含以下屬性:
    • name:指令名,不包括v-前綴。
    • value:指令的綁定值,例如:v-my-directive="1 + 1"中,綁定值為2。
    • oldValue:指令綁定的前一個值,僅在updatecomponentUpdated鉤子中可用。無論值是否改變都可用。
    • expression:字符串形式的指令表達式。例如v-my-directive="1 + 1"中,表達式為"1 + 1"。
    • arg:傳給指令的參數(shù),可選。例如v-my-directive:foo中,參數(shù)為"foo"
    • modifiers:一個包含修飾符的對象。例如:v-my-directive.foo.bar 中,修飾符對象為 { foo: true, bar: true }。
  • vnode:Vue編譯生成的虛擬節(jié)點。
  • oldVnode:上一個虛擬節(jié)點,僅在updatecomponentUpdated鉤子中可用。

除了el之外,其它參數(shù)都應(yīng)該是只讀的,切勿進行修改。如果需要在鉤子之間共享數(shù)據(jù),建議通過元素的 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!'
 }
})

函數(shù)簡寫

在很多時候,你可能想在bindupdate時觸發(fā)相同行為,而不關(guān)心其它的鉤子。比如這樣寫:

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

對象字面量

如果指令需要多個值,可以傳入一個JavaScript對象字面量。記住,指令函數(shù)能夠接受所有合法的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!"
})

插件

開發(fā)插件

插件通常會為Vue添加全局功能。插件的范圍沒有限制——一般有下面幾種:

  1. 添加全局方法或者屬性,如: vue-custom-element
  2. 添加全局資源:指令/過濾器/過渡等,如vue-touch
  3. 通過全局mixin方法添加一些組件選項,如: vue-router
  4. 添加Vue實例方法,通過把它們添加到Vue.prototype上實現(xiàn)。
  5. 一個庫,提供自己的API,同時提供上面提到的一個或多個功能,如vue-router

Vue.js的插件應(yīng)當有一個公開方法install。這個方法的第一個參數(shù)是Vue構(gòu)造器,第二個參數(shù)是一個可選的選項對象:

MyPlugin.install = function (Vue, options) {
 // 1\. 添加全局方法或?qū)傩? Vue.myGlobalMethod = function () {
 // 邏輯...
 }
 // 2\. 添加全局資源
 Vue.directive('my-directive', {
 bind (el, binding, vnode, oldVnode) {
 // 邏輯...
 }
 ...
 })
 // 3\. 注入組件
 Vue.mixin({
 created: function () {
 // 邏輯...
 }
 ...
 })
 // 4\. 添加實例方法
 Vue.prototype.$myMethod = function (methodOptions) {
 // 邏輯...
 }
}

使用插件

通過全局方法Vue.use()使用插件:

// 調(diào)用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)

也可以傳入一個選項對象:

Vue.use(MyPlugin, { someOption: true })

Vue.use 會自動阻止多次注冊相同插件,屆時只會注冊一次該插件。

過濾器

Vue.js允許你自定義過濾器,可被用于一些常見的文本格式化。過濾器可以用在兩個地方:雙花括號插值和v-bind表達式。過濾器應(yīng)該被添加在JavaScript表達式的尾部,由“管道”符號指示:

<!-- 在雙花括號中 -->
{{ message | capitalize }}

<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>

你可以在一個組件的選項中定義本地的過濾器:

filters: {
  capitalize: function (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
}

或者在創(chuàng)建Vue實例之前全局定義過濾器:

Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

new Vue({
  // ...
})

過濾器函數(shù)總接收表達式的值 (之前的操作鏈的結(jié)果) 作為第一個參數(shù)。在上述例子中,capitalize過濾器函數(shù)將會收到message的值作為第一個參數(shù)。
過濾器可以串聯(lián):

{{ message | filterA | filterB }}

在這個例子中,filterA被定義為接收單個參數(shù)的過濾器函數(shù),表達式message的值將作為參數(shù)傳入到函數(shù)中。然后繼續(xù)調(diào)用同樣被定義為接收單個參數(shù)的過濾器函數(shù)filterB,將filterA的結(jié)果傳遞到filterB中。
過濾器是JavaScript函數(shù),因此可以接收參數(shù):

{{ message | filterA('arg1', arg2) }}

這里,filterA被定義為接收三個參數(shù)的過濾器函數(shù)。其中message的值作為第一個參數(shù),普通字符串'arg1'作為第二個參數(shù),表達式arg2的值作為第三個參數(shù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 從接觸angularjs1.x開始,使用并開發(fā)過很多組件和指令,它能極大的擴展web的業(yè)務(wù)處理能力,而且代碼很簡潔...
    老鼠AI大米_Java全棧閱讀 3,559評論 0 4
  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容,還有我對于 Vue 1.0 印象不深的內(nèi)容。關(guān)于...
    云之外閱讀 5,186評論 0 29
  • Vue 實例 屬性和方法 每個 Vue 實例都會代理其 data 對象里所有的屬性:var data = { a:...
    云之外閱讀 2,389評論 0 6
  • vue概述 在官方文檔中,有一句話對Vue的定位說的很明確:Vue.js 的核心是一個允許采用簡潔的模板語法來聲明...
    li4065閱讀 7,627評論 0 25
  • 以下內(nèi)容是我在學習和研究Vue時,對Vue的特性、重點和注意事項的提取、精練和總結(jié),可以做為Vue特性的字典; 1...
    科研者閱讀 14,226評論 3 24

友情鏈接更多精彩內(nèi)容