Vue 中有許多的指令提供我們使用。它可以讓你進行一些模版的操作。
但是內建指令,在實際的開發過程中可能這些並不能滿足所有的需求。所以 Vue 給我們提供來一個靈活的方法「自定義指令」。
說自定義指令之前,先看看什麼叫「指令」。
指令的概念
指令是指可以控制操作 DOM 的一些小命令,通常以 v-
字首出現的特殊特性。
例如我們經常使用的v-if
、v-show
、v-bind
、v-on
、v-html
等。
使用指令時,你可以傳遞值,字串,也可以給指令新增引數,修飾符等等。比如:
1.傳遞值
<p v-if="isShow">你好,我是六哥</p>
let vm = new Vue({
el: "#app",
data: {
isShow: true
}
});
複製程式碼
2.字串
<p v-text="'hello world'"></p>
複製程式碼
3.新增引數
// class,style 就是傳給指令的引數
<div v-bind:class="classObj"></div>
<div v-bind:style="classObj"></div>
複製程式碼
4.修飾符
// prevent 指令的修飾符
<button v-on:submit.prevent="onSubmit"></button>
複製程式碼
以上是你經常使用指令的方式,瞭解這些之後,它可以幫助我們更好的認識自定義指令的 一些引數問題。下面就來看看自定義指令。
自定義指令
指令的註冊方式和「過濾器」、「混入」、「元件」註冊的方式一樣都分為兩種:一是全域性註冊,二是區域性註冊。
1.全域性註冊
Vue.directive('name', {})
複製程式碼
2.區域性註冊
directives: {
name: {}
}
複製程式碼
然後在模版中直接使用即可。
<p v-name>你好,六哥在這</p>
複製程式碼
我個人更傾向於使用全域性註冊的方式,因為既然已經使用了自定義指令,應該是通用,可複用的。
所以提供整個專案使用的指令才更有價值,而不僅僅只限於某個元件內部。如果單一地方使用直接把功能摟出就行了,何必費這力氣。
繼續來看具體的實現方式。
Vue 提供了自定義指令的幾個鉤子函式:
- bind:指令第一次繫結到元素時呼叫,只執行一次。
- inserted:被繫結的元素,插入到父節點的 DOM 中時呼叫。
- update:元件更新時呼叫。
- componentUpdated:元件與子元件更新時呼叫。
- unbind:指令與元素解綁時呼叫,只執行一次。
除update 與 componentUpdated 鉤子函式之外,每個鉤子函式都含有 el
、binding
、vnode
這三個引數。
oldVnode
只有在 update 與 componentUpdated 鉤子中生效。
引數el
就是指令繫結的 DOM 元素,而binding
是一個物件,它包含一下屬性:name
、value
、oldValue
、expression
、arg
、modifiers
。
另外值得注意的一點是,除了 el
之外,binding
、vnode
屬性都是隻讀的。
熟悉指令的建立方式與引數之後,我們就用它來建立一個案例。
建立自定義指令
Loading 是專案中最常見的一個小功能,別看它功能小,但是起到的作用卻很大,手動建立一個 Loading 指令。
Vue.directive("loading", {
bind(el, binding) {
if (binding.value) {
let div = document.createElement("div");
div.className = "loading-parent";
div.innerHTML = `
<div class="loading-spinner"><i class='el-icon-loading'></i></div>
`;
el.appendChild(div);
}
},
update(el, binding) {
if (binding.value) {
let div = document.createElement("div");
div.className = "loading-parent";
div.innerHTML = `
<div class="loading-spinner"><i class='el-icon-loading'></i></div>
`;
el.appendChild(div);
el.load = div;
} else {
el.load && el.load.parentNode && el.load.parentNode.removeChild(el.load);
}
}
});
複製程式碼
然後我們直接就可以在模版中使用了。
<div v-loading="loading" class="box"></div>
複製程式碼
你也看出來了很多程式碼是重複的,怎麼辦呢?
Vue 中給我們提供了簡寫方式。當只有這兩個鉤子函式時bind
與 update
,我們可以簡寫如下。
Vue.directive("loading", function(el, binding) {
if (binding.value) {
let div = document.createElement("div");
div.className = "loading-parent";
div.innerHTML = `
<div class="loading-spinner"><i class='el-icon-loading'></i></div>
`;
el.appendChild(div);
el.load = div;
} else {
el.load && el.load.parentNode && el.load.parentNode.removeChild(el.load);
}
});
複製程式碼
我們實現了一個非常簡單的指令,但還不夠靈活,比如我想新增 loading 的背景色,修改圖示的顏色怎麼辦呢?
這時候就需要給指令傳入多個值,改造下實現背景與圖示顏色。
Vue.directive("loading", function(el, binding) {
if (binding.value) {
let div = document.createElement("div");
div.className = "loading-parent";
div.style.backgroundColor = binding.value.background;
div.style.color = binding.value.color;
div.innerHTML = `
<div class="loading-spinner"><i class='el-icon-loading'></i></div>
`;
el.appendChild(div);
el.load = div;
} else {
el.load && el.load.parentNode && el.load.parentNode.removeChild(el.load);
}
});
複製程式碼
直接使用
<div v-loading="{color: 'white', background: '#000'}">我可以擁有更多屬性</div>
複製程式碼
在文章開始我們介紹指令時,還說到指令的「引數」與「修飾符」這裡我就不多介紹了,大家不妨自己去嘗試一下吧。體驗下自定義指令的魅力。
如果文章對你有啟發,記得給個贊哦。
公眾號:六小登登,更多幹貨文章。
人人都可以成為高手。一個愛寫作的技術人。歡迎交流。