除了核心功能默認內置的指令 (v-model
和 v-show
),Vue 也容許註冊自定義指令。注意,在 Vue2.0
中,代碼複用和抽象的主要形式是組件。然而,有的狀況下,你仍然須要對普通 DOM 元素進行底層操做,這時候就會用到自定義指令。vue
來個實例,當頁面加載時,該input元素將得到焦點:node
// 註冊一個全局自定義指令 `v-focus` Vue.directive('focus', { // 當被綁定的元素插入到 DOM 中時…… inserted: function (el) { // 聚焦元素 el.focus() } })
若是想註冊局部指令,組件中也接受一個 directives
的選項:webpack
directives: { focus: { // 指令的定義 inserted: function (el) { el.focus() } } }
而後你能夠在模板中任何元素上使用新的 v-focus 屬性,以下:git
<input v-focus>
一個指令定義對象能夠提供以下幾個鉤子函數 (均爲可選):github
bind
:只調用一次,指令第一次綁定到元素時調用。在這裏能夠進行一次性的初始化設置。inserted
:被綁定元素插入父節點時調用 (僅保證父節點存在,但不必定已被插入文檔中)。update
:所在組件的 VNode 更新時調用,可是可能發生在其子 VNode 更新以前。指令的值可能發生了改變,也可能沒有。可是你能夠經過比較更新先後的值來忽略沒必要要的模板更新 (詳細的鉤子函數參數見下)。componentUpdated
:指令所在組件的 VNode 及其子 VNode 所有更新後調用。unbind
:只調用一次,指令與元素解綁時調用。接下來咱們來看一下鉤子函數的參數 (即 el
、binding
、vnode
和 oldVnode
)。web
指令鉤子函數會被傳入如下參數:vue-router
el
:指令所綁定的元素,能夠用來直接操做 DOM 。binding
:一個對象,包含如下屬性:express
name
:指令名,不包括 v- 前綴。value
:指令的綁定值,例如:v-my-directive="1 + 1"
中,綁定值爲 2
。oldValue
:指令綁定的前一個值,僅在 update
和 componentUpdated
鉤子中可用。不管值是否改變均可用。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
:上一個虛擬節點,僅在 update
和 componentUpdated
鉤子中可用。
除了
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!' } })
結果:async
name: "demo" value: "hello!" expression: "message" argument: "foo" modifiers: {"a":true,"b":true} vnode keys: tag, data, children, text, elm, ns, context, fnContext, fnOptions, fnScopeId, key, componentOptions, componentInstance, parent, raw, isStatic, isRootInsert, isComment, isCloned, isOnce, asyncFactory, asyncMeta, isAsyncPlaceholder
在不少時候,你可能想在 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!" })
插件一般會爲 Vue 添加全局功能。插件的範圍沒有限制——通常有下面幾種:
Vue.js 的插件應當有一個公開方法 install
。這個方法的第一個參數是 Vue
構造器,第二個參數是一個可選的選項對象:
MyPlugin.install = function (Vue, options) { // 1. 添加全局方法或屬性 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()
使用插件:
// 調用 `MyPlugin.install(Vue)` Vue.use(MyPlugin)
也能夠傳入一個選項對象:
Vue.use(MyPlugin, { someOption: true })
Vue.use
會自動阻止屢次註冊相同插件,屆時只會註冊一次該插件。
Vue.js
官方提供的一些插件 (例如 vue-router) 在檢測到 Vue 是可訪問的全局變量時會自動調用 Vue.use()
。然而在例如 CommonJS 的模塊環境中,你應該始終顯式地調用 Vue.use()
:
// 用 Browserify 或 webpack 提供的 CommonJS 模塊環境時 var Vue = require('vue') var VueRouter = require('vue-router') // 不要忘了調用此方法 Vue.use(VueRouter)
封裝一個全局的插件,以下:
在src下的components文件夾下新建一個countdown文件夾,新建一個countdown.vue文件:
<template> <div>封裝一個最簡單的插件</div> </template> <script> export default{ name:'count-down' } </script>
在放countdown.vue的同級目錄下新建一個index.js:
import countDown from './countdown'; countDown.install = function(Vue){ Vue.component(countDown.name,countDown) }; export default countDown;
在main.js中:
import countDown from './components/countdown/index.js' Vue.use(countDown)
在組件中就能夠這樣使用了:
<count-down></count-down>
混合 (mixins
) 是一種分發 Vue 組件中可複用功能的很是靈活的方式。混合對象能夠包含任意組件選項。當組件使用混合對象時,全部混合對象的選項將被混入該組件自己的選項。
// 定義一個混合對象 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!"
當組件和混合對象含有同名選項時,這些選項將以恰當的方式混合。好比,同名鉤子函數將混合爲一個數組,所以都將被調用。另外,混合對象的 鉤子將在組件自身鉤子 以前 調用 :
var mixin = { created: function () { console.log('混合對象的鉤子被調用') } } new Vue({ mixins: [mixin], created: function () { console.log('組件鉤子被調用') } }) // => "混合對象的鉤子被調用" // => "組件鉤子被調用"
值爲對象的選項,例如 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()
也使用一樣的策略進行合併。
也能夠全局註冊混合對象。注意使用! 一旦使用全局混合對象,將會影響到 全部 以後建立的 Vue 實例。使用恰當時,能夠爲自定義對象注入處理邏輯。
// 爲自定義的選項 'myOption' 注入一個處理器。 Vue.mixin({ created: function () { var myOption = this.$options.myOption if (myOption) { console.log(myOption) } } }) new Vue({ myOption: 'hello!' }) // => "hello!"
謹慎使用全局混合對象
,由於會影響到每一個單首創建的 Vue 實例 (包括第三方模板)。大多數狀況下,只應當應用於自定義選項,就像上面示例同樣。也能夠將其用做 Plugins 以免產生重複應用
自定義選項將使用默認策略,即簡單地覆蓋已有值。若是想讓自定義選項以自定義邏輯合併,能夠向 Vue.config.optionMergeStrategies
添加一個函數:
Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) { // return mergedVal }
對於大多數對象選項,可使用 methods 的合併策略:
var strategies = Vue.config.optionMergeStrategies strategies.myOption = strategies.methods