Vue.directive(id, definition)
傳入的兩個參數,id是指指令ID,definition是指定義對象。其中,定義對象能夠提供一些鉤子函數web
鉤子函數express
一個指令定義對象能夠提供以下幾個鉤子函數 (均爲可選):api
-
bind
:只調用一次,指令第一次綁定到元素時調用。在這裏能夠進行一次性的初始化設置。app
-
inserted
:被綁定元素插入父節點時調用 (僅保證父節點存在,但不必定已被插入文檔中)。ide
-
update
:所在組件的 VNode 更新時調用,可是可能發生在其子 VNode 更新以前。指令的值可能發生了改變,也可能沒有。可是你能夠經過比較更新先後的值來忽略沒必要要的模板更新 (詳細的鉤子函數參數見下)。函數
咱們會在稍後討論渲染函數時介紹更多 VNodes 的細節。動畫
接下來咱們來看一下鉤子函數的參數 (即 el
、binding
、vnode
和 oldVnode
)。
鉤子函數參數
指令鉤子函數會被傳入如下參數:
el
:指令所綁定的元素,能夠用來直接操做 DOM 。
binding
:一個對象,包含如下屬性:vnode
:Vue 編譯生成的虛擬節點。移步 VNode API 來了解更多詳情。
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 }
。
oldVnode
:上一個虛擬節點,僅在 update
和 componentUpdated
鉤子中可用。
除了 el
以外,其它參數都應該是隻讀的,切勿進行修改。若是須要在鉤子之間共享數據,建議經過元素的 dataset
來進行。
這是一個使用了這些屬性的自定義鉤子樣例:
Vue.directive('my-directive', { bind: function(){ //作綁定的準備工做
//好比添加事件監聽器,或是其餘只須要執行一次的複雜操做
}, inserted: function(){ //...
}, update: function(){ //根據得到的新值執行對應的更新
//對於初始值也會調用一次
}, componentUpdated: function(){ //...
}, unbind: function(){ //作清理操做
//好比移除bind時綁定的事件監聽器
}
官網文檔:https://cn.vuejs.org/v2/guide/custom-directive.html
使用場景
- 代碼複用和抽象的主要形式是組件
- 當須要對普通 DOM 元素進行底層操做,此時就會用到自定義指令
- 可是,對於大幅度的 DOM 變更,仍是應該使用組件
3. 示例
3.1 輸入框自動聚焦
// 註冊一個全局自定義指令 `v-focus`
Vue.directive('focus', { // 當被綁定的元素插入到 DOM 中時
inserted: function (el) { // 聚焦元素
el.focus() } }) <input v-focus>
3.2 下拉菜單
- 點擊下拉菜單自己不會隱藏菜單
- 點擊下拉菜單之外的區域隱藏菜單
Vue.directive('clickoutside', { bind(el, binding) { function documentHandler(e) { if (el.contains(e.target)) { return false } if (binding.expression) { binding.value(e) } } el.__vueMenuHandler__ = documentHandler document.addEventListener('click', el.__vueMenuHandler__) }, unbind(el) { document.removeEventListener('click', el.__vueMenuHandler__) delete el.__vueMenuHandler__ } }) new Vue({ el: '#app', data: { show: false }, methods: { handleHide() { this.show = false } } })
<div class="main" v-menu="handleHide">
<button @click="show = !show">點擊顯示下拉菜單</button>
<div class="dropdown" v-show="show">
<div class="item"><a href="#">選項 1</a></div>
<div class="item"><a href="#">選項 2</a></div>
<div class="item"><a href="#">選項 3</a></div>
</div>
</div>
3.3 相對時間轉換
相似微博、朋友圈發佈動態後的相對時間,好比剛剛、兩分鐘前等等
<span v-relativeTime="time"></span> new Vue({ el: '#app', data: { time: 1565753400000 } }) Vue.directive('relativeTime', { bind(el, binding) { // Time.getFormatTime() 方法,自行補充 el.innerHTML = Time.getFormatTime(binding.value) el.__timeout__ = setInterval(() => { el.innerHTML = Time.getFormatTime(binding.value) }, 6000) }, unbind(el) { clearInterval(el.innerHTML) delete el.__timeout__ } })
3.4 滾動動畫
<div id="app">
<h1 class="centered">Scroll me</h1>
<div class="box" v-scroll="handleScroll">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. A atque amet harum aut ab veritatis earum porro praesentium ut corporis. Quasi provident dolorem officia iure fugiat, eius mollitia sequi quisquam.</p>
</div>
</div>
Vue.directive('scroll', { inserted: function(el, binding) { let f = function(evt) { if (binding.value(evt, el)) { window.removeEventListener('scroll', f) } } window.addEventListener('scroll', f) } }) // main app
new Vue({ el: '#app', methods: { handleScroll: function(evt, el) { if (window.scrollY > 50) { TweenMax.to(el, 1.5, { y: -10, opacity: 1, ease: Sine.easeOut }) } return window.scrollY > 100 } } })
body { font-family: 'Abhaya Libre', Times, serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; background: #000; color: #fff; overflow-x: hidden;
} h1, h2, h3, h4 { font-family: 'Fira Sans', Helvetica, Arial, sans-serif; font-weight: 800;
} .centered { margin: 0 auto; display: table; font-size: 60px; margin-top: 100px;
} .box { border: 1px solid rgba(255, 255, 255, 0.5); padding: 8px 20px; line-height: 1.3em; opacity: 0; color: white; width: 200px; margin: 0 auto; margin-top: 30px; transform: translateZ(0); perspective: 1000px; backface-visibility: hidden; background: rgba(255, 255, 255, 0.1);
} #app { height: 2000px;
}
自定義指令:
屬性:
Vue.directive(指令名稱,function(參數){
this.el -> 原生DOM元素
});
<div v-red="參數"></div>
指令名稱: v-red -> red
* 注意: 必須以 v-開頭
拖拽:
-------------------------------
自定義元素指令:(用處不大)
Vue.elementDirective('zns-red',{
bind:function(){
this.el.style.background='red';
}
});
------------------------------------------------
@keydown.up
@keydown.enter
@keydown.a/b/c....
自定義鍵盤信息:
Vue.directive('on').keyCodes.ctrl=17;
Vue.directive('on').keyCodes.myenter=13;
------------------------------------------------