概述
除了 Vue 原生的 v-model、v-show 等等指令外,Vue 也允許註冊 自定義指令(Custom Directives)。
Vue 不建議透過 document.querySelector 等方式直接選取 DOM 操作 DOM。但在開發過程中某些情況下還是有需要對底層 DOM 元素進行操作需求。
- 在 Vue 中,可以透過
ref 來取得 DOM;
- 或者透過 自定義指令,封裝可重複使用的 DOM 操作功能。
簡單範例
當我們想要載入頁面時,讓某個表單元素自動獲取焦點,可以使用 autofocus 特性,但 iOS Safari 不支援。
這裡我們使用自定義指令來實現類似的效果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<script>
const focus = {
mounted(el) {
el.focus();
},
};
export default {
directives: { focus },
};
</script>
<template>
<input v-focus />
</template>
|
註冊
自定義指令的註冊方式分成兩種:
鉤子函式
一個指令定義物件可以提供如下幾個鉤子函數(均為可選):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
const myDirective = {
created(el, binding, vnode) {
// 在綁定元素的 attribute 或事件監聽器被應用之前呼叫(v-on 之前)
},
beforeMount(el, binding, vnode) {
// 當指令第一次綁定到元素並且在掛載父元件之前呼叫
},
mounted(el, binding, vnode) {
// 綁定元素的父元件被掛載時呼叫
},
beforeUpdate(el, binding, vnode, prevNode) {
// 在包含元件的 VNode 更新之前呼叫
},
updated(el, binding, vnode, prevNode) {
// 在包含元件的 VNode 及其子元件的 VNode 更新之後呼叫
},
beforeUnmount(el, binding, vnode) {
// 在綁定元素的父元件卸載之前呼叫
},
unmounted(el, binding, vnode) {
// 卸載綁定元素的父元件時呼叫
},
};
|
鉤子函式參數
除了 el 之外,其餘參數都應該視為唯讀,請勿進行修改。若要在鉤子之間共享資料,建議透過元素的 dataset 來進行。
1. el
使用指令的元素。這可用於直接操作 DOM。
2. binding
binding 為物件,包含以下屬性:
instance:使用指令的元件實體。
value:傳遞給指令的值。
oldValue:更新前的值,只在 beforeUpdate 和 updated 中可以使用。
arg:參數。
modifiers:包含修飾符號的物件。
- 例:
v-demo.a 會得到 { a: true }
dir:指令物件。
3. vnode
虛擬節點。
4. prevNode
上一個虛擬節點,只在 beforeUpdate 和 updated 鉤子中可以使用。
函式簡寫
在很多時候,我們會在 mounted 和 updated 時觸發相同行為,而不關心其它的鉤子,Vue 為此提供了簡寫,傳遞一個函式:
1
2
3
|
const myDirective = (el, binding)=> {
// ...
};
|
在元件上使用
- 指令也可以用在 Vue 的元件上,將會被應用在元件的根結點上;
- 但要注意,指令無法透過
v-bind="$attrs" 被傳入到另一個元素;
- 若元件包含多個根結點,指令將會被忽略,並且拋出警告。
簡單應用
使用自定義指令簡易封裝 Bootstrap 5 的 Tooltips。
- value:內容
v-tooltip="'內容'"
- arg:方向
v-tooltip:right="'內容'"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
const { Tooltip } = bootstrap;
function tooltipInit(el, { value, arg }) {
const tooltip = new Tooltip(el, {
title: value,
trigger: 'hover',
placement: arg,
});
return tooltip;
}
const tooltip = {
mounted(el, { value, arg = 'auto' }) {
const tooltip = tooltipInit(el, { value, arg });
el.$tooltip = tooltip;
},
updated(el, { value, arg = 'auto' }) {
el.$tooltip.disable();
const tooltip = tooltipInit(el, { value, arg });
el.$tooltip = tooltip;
},
unmounted(el) {
el.$tooltip.disable();
},
};
|