.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:N190821001
出刊日期:2019/8/7
在這篇文章將延續本站《Vue.js入門》系列文章,來介紹如何設計自定義指令(Custom Directive)。回顧一下,指令(Directives)是前置「v-」符號的特殊特性(Attribute),讓你可以透過Vue套用一些特效到DOM物件上。預設Vue提供多樣的指令來供你使用,例如「v-if」、「v-show」、「v-else」、「v-model」、「v-bind」等等。
除了這些預設的指令之外,Vue可以讓你自定指令,在Vue 2.0版,建議達到重複使用的單位是「組件(Component)」,若在不同的組件之中,仍有需要共用的部分,就可以將之設計成自定義指令(Custom Directive)。
一個指令只會有一個參數(Argument),指令語法:
v-指令名稱:參數
v-DirectiveName:Argument
我們回顧一下系列文章中介紹過的範例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title> Document </title>
</head>
<body>
<div id="divMsg">
<h1 v-on:click="showMsg"> {{ msg }} </h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#divMsg',
data: {
msg: 'Hello',
},
methods: {
showMsg: function (event) {
alert(this.msg);
}
}
});
</script>
</body>
</html>
這個範例程式執行後,只要點選網頁中的<h1>標題,就會顯示一個「Hello」訊息。範例中使用了Vue內建的「v-on」指令:
<h1 v-on:click="showMsg">
這個範例中指令(Directive)的名稱是「on」,參數(Argument)是「click」,「showMsg」則是傳遞到指令的值。
指令中也可以包含修飾符(Modifier),語法如下 :
v-指令名稱:參數.修飾符
v-DirectiveName:Argument.Modifiers
指令後方可以加上零到多個修飾符(Modifier),例如我們可以修改上例,加上「once」修飾符,讓事件只有第一次生效:
<h1 v-on:click.once="showMsg"> {{ msg }} </h1>
此外,修飾符可以有多個,只要使用「.」號做區隔,語法如下:
v-指令名稱:引數.修飾符1.修飾符2
v-DirectiveName:Argument.Modifier1.Modifier2
自定義指令(Custom Directive)
指令定義物件(directive definition object)提供多種選擇性鉤子函式(hook function)可以使用,包含:「bind」、「inserted」、「update」、「componentUpdated」、「unbind」等等,最常使用的是「bind」與「update」這兩個函式,以下是使用自定義指令搭配「bind」函式的語法:
Vue.directive('自定義指令名稱', {
bind(e1, binding, vnode) {
}
})
接下來我們想要定義一個按鈕,利用自定義指令,讓它固定出現在網頁右下方,可以透過這個按鈕將網頁畫面捲動到網頁最上方,參考以下範例程式碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title> Document </title>
</head>
<body>
<div id="divMsg">
<button v-gototop>^</button>
<h1>Home</h1>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Dignissimos, repellat! Eius eaque tenetur ad dignissimos
... 略
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
Vue.directive("gototop", {
bind(el, binding, vnode) {
el.style.position = "fixed";
el.style.width = "45px";
el.style.height = "45px";
el.style.opacity = "0.8";
el.style.right = "50px";
el.style.bottom = "30px";
el.style.cursor = "pointer";
el.style.border = "none";
el.style.outline = "none";
el.style.fontSize = "24px";
el.style.background = "pink";
el.addEventListener('click', () => {
document.documentElement.scrollTop = 0;
});
}
});
var vm = new Vue({
el: '#divMsg',
data: {}
});
</script>
</body>
</html>
注意,自定義指令(Custom Directive)必需在Vue實體建立之前,先註冊好。範例中使用「Vue.directive」建立自定義指令(Custom Directive),名稱為「gototop」,然後在<button>標籤套用「v-gototop」指令。
「bind」函式包含三個參數:
- 「el」:套用「v-gototop」指令的HTML項目。
- 「binding」:參數物件,包含自定義指令的「name」、「modifiers」、「rawName」...等資訊。
- 「vnode」:用來參考到virtual DOM。
我們在「bind」函式之中利用「style」屬性,設定了繫結對象(Button)的樣式,例如固定位置(position = "fixed")、寬度(width)、高度(hight)、透明度(opacity)...等等,並且註冊了「click」事件,當繫結對象被點選時,便設定「scrollTop」屬性為「0」,這樣便可以讓網頁捲動到最上方。這個範例程式的執行結果參考如下,網頁的右下方會出現回到最上面的按鈕(gototop):

圖 1:套用「v-gototop」指令的HTML項目。
當捲動到網頁下方,點選按鈕,畫面就會捲動到最上面,請參考下圖所示:

圖 2:點選HTML項目畫面就會捲動到最上面。
簡寫語法
大部分情況下,只需要使用到「bind」、「update」函式,如果不考慮到使用其它鉤子函式(hook function),可以使用簡寫版語法來定義自定義指令,語法如下:
Vue.directive('自定義指令名稱', function(e1, binding, vnode) {
})
上例的自定義指令範例可以改寫如下,執行將會得到相同的結果:
Vue.directive("gototop", function (el, binding, vnode) {
el.style.position = "fixed";
el.style.width = "45px";
el.style.height = "45px";
el.style.opacity = "0.8";
el.style.right = "50px";
el.style.bottom = "30px";
el.style.cursor = "pointer";
el.style.border = "none";
el.style.outline = "none";
el.style.fontSize = "24px";
el.style.background = "pink";
el.addEventListener('click', () => {
document.documentElement.scrollTop = 0;
});
});
傳遞值到自定義指令
上面的範例寫死了樣式,將繫結對象的背景顏色設定為「pink」色,如此不夠有彈性。我們要改良一下上述的自定義指令範例,讓你可以在HTML標籤套用「v-gototop」時,可以傳遞想使用的背景顏色到自定義指令,參考以下範例程式碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title> Document </title>
</head>
<body>
<div id="divMsg">
<button v-gototop="'lightblue'">^</button>
<h1>Home</h1>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Dignissimos, repellat! Eius eaque tenetur ad dignissimos
...略
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
Vue.directive("gototop", function (el, binding, vnode) {
el.style.background = binding.value;
el.style.position = "fixed";
el.style.width = "45px";
el.style.height = "45px";
el.style.opacity = "0.8";
el.style.right = "50px";
el.style.bottom = "30px";
el.style.cursor = "pointer";
el.style.border = "none";
el.style.outline = "none";
el.style.fontSize = "24px";
el.addEventListener('click', () => {
document.documentElement.scrollTop = 0;
});
});
var vm = new Vue({
el: '#divMsg',
data: {}
});
</script>
</body>
</html>
我們在<button v-gototop="'lightblue'">標籤設定想傳遞的背景顏色為「'lightblue'」,傳遞的值是字串,因此使用單引號包起來,而在自定義指令中,便可以使用「binding.value」來取得傳遞過來的值。這樣我們的自訂義指令的彈性便會比較大。
傳遞參數(Argument)
在套用「v-gototop」自定義指令時,可以傳遞參數到自定義指令。我們來修改上個範例,讓自定義指令可以接收一個參數,名稱為「bgcolor」:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title> Document </title>
</head>
<body>
<div id="divMsg">
<button v-gototop:bgcolor="'lightblue'">^</button>
<h1>Home</h1>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Dignissimos, repellat! Eius eaque tenetur ad dignissimos
...略
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
Vue.directive("gototop", function (el, binding, vnode) {
let bgColor = binding.arg === undefined ? "pink" : binding.value;
el.style.background = bgColor;
el.style.position = "fixed";
el.style.width = "45px";
el.style.height = "45px";
el.style.opacity = "0.8";
el.style.right = "50px";
el.style.bottom = "30px";
el.style.cursor = "pointer";
el.style.border = "none";
el.style.outline = "none";
el.style.fontSize = "24px";
el.addEventListener('click', () => {
document.documentElement.scrollTop = 0;
});
});
var vm = new Vue({
el: '#divMsg',
data: {}
});
</script>
</body>
</html>
「binding」物件包含一個「arg」屬性,裏頭便包含你傳入自定義指令的「bgcolor」,若套用自定義指令時,沒有設定「bgcolor」:
<button v-gototop="'lightblue'">^</button>
「binding.arg」就會是「undefined」,為了簡單起見,未設定「bgcolor」時,我們在程式中便設定使用預設的「pink」當背景顏色;若有設定「bgcolor」時,就會套用「lightblue」當背景顏色。這個範例程式的執行結果參考如下,使用參數設定背景顏色為藍色:

圖 3:使用參數設定背景顏色為藍色。