混入
基礎(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,components和directives,將被混合為同一個對象。兩個對象鍵名沖突時,取組件對象的鍵值對。
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:指令綁定的前一個值,僅在update和componentUpdated鉤子中可用。無論值是否改變都可用。 -
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é)點,僅在update和componentUpdated鉤子中可用。
除了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ù)簡寫
在很多時候,你可能想在bind和update時觸發(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添加全局功能。插件的范圍沒有限制——一般有下面幾種:
- 添加全局方法或者屬性,如: vue-custom-element
- 添加全局資源:指令/過濾器/過渡等,如vue-touch
- 通過全局
mixin方法添加一些組件選項,如: vue-router - 添加Vue實例方法,通過把它們添加到
Vue.prototype上實現(xiàn)。 - 一個庫,提供自己的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ù)。