簡述
Vue除了提供了預設内置的指令外,還允許開發人員根據實際情況自定義指令,它的作用價值在于當開發人員在某些場景下需要對普通DOM元素進行操作的時候。
一、注冊自定義指令
Vue自定義指令群組件一樣存在着全局注冊和局部注冊兩種方式。先來看看注冊全局指令的方式,通過
Vue.directive( id, [definition] )
方式注冊全局指令,第一個參數為自定義指令名稱(
指令名稱不需要加v-
字首,預設是自動加上字首的,使用指令的時候一定要加上字首 ),第二個參數可以是對象資料,也可以是一個指令函數。
<div id="app" class="demo">
<!-- 全局注冊 -->
<input type="text" placeholder="我是全局自定義指令" v-focus>
</div>
<script>
Vue.directive("focus", {
inserted: function(el){
el.focus();
}
})
new Vue({
el: "#app"
})
</script>
這個簡單案例當中,我們通過注冊一個
v-focus
指令,實作了在頁面加載完成之後自動讓輸入框擷取到焦點的小功能。其中
inserted
是自定義指令的鈎子函數,後面的内容會詳細講解。
全局注冊好了,那麼再來看看如何注冊局部自定義指令,通過在Vue執行個體中添加
directives
對象資料注冊局部自定義指令。
<div id="app" class="demo">
<!-- 局部注冊 -->
<input type="text" placeholder="我是局部自定義指令" v-focus2>
</div>
<script>
new Vue({
el: "#app",
directives: {
focus2: {
inserted: function(el){
el.focus();
}
}
}
})
</script>
二、鈎子函數
一個指令定義對象可以提供如下幾個鈎子函數 (均為可選):
-
:隻調用一次,指令第一次綁定到元素時調用。在這裡可以進行一次性的初始化設定。bind
-
:被綁定元素插入父節點時調用 (僅保證父節點存在,但不一定已被插入文檔中)。inserted
-
:所在元件的 VNode 更新時調用。update
-
:指令所在元件的 VNode 及其子 VNode 全部更新後調用。componentUpdated
-
:隻調用一次,指令與元素解綁時調用。unbind
官方文檔:
自定義指令 — Vue.jscn.vuejs.org

那麼這幾個鈎子函數怎麼使用呢?先來看看鈎子函數的幾個參數吧。指令鈎子函數會被傳入以下參數:
- el : 指令所綁定的元素,可以用來直接操作 DOM,就是放置指令的那個元素。
- binding : 一個對象,裡面包含了幾個屬性,這裡不多展開說明,官方文檔上都有很詳細的描述。
- vnode :Vue 編譯生成的虛拟節點。
- oldVnode :上一個虛拟節點,僅在 update 和 componentUpdated 鈎子中可用。
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
<script>
Vue.directive('demo', function (el, binding) {
console.log(binding.value.color) // "white"
console.log(binding.value.text) // "hello!"
})
</script>
說了這麼多理論知識,那麼現在就來動手寫一個簡單的案例吧。假設這樣的看一個場景:
當你在閱覽某網站的圖檔時,可能會由于圖檔資源比較大而加載緩慢,需要消耗一小段時間來呈現到眼前,這個體驗肯定是不太友好的(就像網站切換頁面,有時候會加載資源比較慢,為了給使用者較好的體驗,一般都會先出一個正在加載的友好提示頁面),是以這個案例的功能就是在圖檔資源還沒加載出來時,先顯示預設背景圖,當圖檔資源真正加載出來了之後,再把真實圖檔放置到對應的位置上并顯示出來。
<div id="app2" class="demo">
<div v-for="item in imageList">
<img src="../assets/image/bg.png" alt="預設圖" v-image="item.url">
</div>
</div>
<script>
Vue.directive("image", {
inserted: function(el, binding) {
//為了真實展現效果,用了延時操作
setTimeout(function(){
el.setAttribute("src", binding.value);
}, Math.random() * 1200)
}
})
new Vue({
el: "#app2",
data: {
imageList: [
{
url: "http://consumer-img.huawei.com/content/dam/huawei-cbg-site/greate-china/cn/mkt/homepage/section4/home-s4-p10-plus.jpg"
},
{
url: "http://consumer-img.huawei.com/content/dam/huawei-cbg-site/greate-china/cn/mkt/homepage/section4/home-s4-watch2-pro-banner.jpg"
},
{
url: "http://consumer-img.huawei.com/content/dam/huawei-cbg-site/en/mkt/homepage/section4/home-s4-matebook-x.jpg"
}
]
}
})
</script>