做(zuò)自(zì)由與創造的先行(xíng)者

自(zì)定義指令

Vue.js中文手冊

介紹

除了(le) Vue 內(nèi)置的一(yī)系列指令 (比如(rú) v-model 或 v-show) 之外(wài),Vue 還允許你注冊自(zì)定義的指令 (Custom Directives)。

我們已經介紹了(le)兩種在 Vue 中重用代碼的方式:組件和(hé)組合式函數(shù)。組件是主要(yào)的構建模塊,而組合式函數(shù)則側重于有狀态的邏輯。另一(yī)方面,自(zì)定義指令主要(yào)是為(wèi)了(le)重用涉及普通(tōng)元素的底層 DOM 訪問(wèn)的邏輯。

一(yī)個自(zì)定義指令由一(yī)個包含類似組件生命周期鈎子的對象來定義。鈎子函數(shù)會接收到指令所綁定元素作(zuò)為(wèi)其參數(shù)。下(xià)面是一(yī)個自(zì)定義指令的例子,當一(yī)個 input 元素被 Vue 插入到 DOM 中後,它會被自(zì)動聚焦:

js

const focus = {

mounted: (el) => el.focus()

}

export default {

directives: {

// 在模闆中啓用 v-focus

focus

}

}

template

<input v-focus />

假設你還未點擊頁面中的其他(tā)地(dì)方,那(nà)麽上(shàng)面這(zhè)個 input 元素應該會被自(zì)動聚焦。該指令比 autofocus attribute 更有用,因為(wèi)它不僅僅可(kě)以在頁面加載完成後生效,還可(kě)以在 Vue 動态插入元素後生效。

和(hé)組件類似,自(zì)定義指令在模闆中使用前必須先注冊。在上(shàng)面的例子中,我們使用 directives 選項完成了(le)指令的局部注冊。

将一(yī)個自(zì)定義指令全局注冊到應用層級也是一(yī)種常見(jiàn)的做(zuò)法:

js

const app = createApp({})

// 使 v-focus 在所有組件中都(dōu)可(kě)用

app.directive('focus', {

/* ... */

})

TIP

隻有當所需功能(néng)隻能(néng)通(tōng)過直接的 DOM 操作(zuò)來實現時(shí),才應該使用自(zì)定義指令。其他(tā)情況下(xià)應該盡可(kě)能(néng)地(dì)使用 v-bind 這(zhè)樣的內(nèi)置指令來聲明(míng)式地(dì)使用模闆,這(zhè)樣更高效,也對服務端渲染更友(yǒu)好。

指令鈎子

一(yī)個指令的定義對象可(kě)以提供幾種鈎子函數(shù) (都(dōu)是可(kě)選的):

js

const myDirective = {

// 在綁定元素的 attribute 前

// 或事件監聽器應用前調用

created(el, binding, vnode, prevVnode) {

// 下(xià)面會介紹各個參數(shù)的細節

},

// 在元素被插入到 DOM 前調用

beforeMount(el, binding, vnode, prevVnode) {},

// 在綁定元素的父組件

// 及他(tā)自(zì)己的所有子節點都(dōu)挂載完成後調用

mounted(el, binding, vnode, prevVnode) {},

// 綁定元素的父組件更新前調用

beforeUpdate(el, binding, vnode, prevVnode) {},

// 在綁定元素的父組件

// 及他(tā)自(zì)己的所有子節點都(dōu)更新後調用

updated(el, binding, vnode, prevVnode) {},

// 綁定元素的父組件卸載前調用

beforeUnmount(el, binding, vnode, prevVnode) {},

// 綁定元素的父組件卸載後調用

unmounted(el, binding, vnode, prevVnode) {}

}

鈎子參數(shù)

指令的鈎子會傳遞以下(xià)幾種參數(shù):

el:指令綁定到的元素。這(zhè)可(kě)以用于直接操作(zuò) DOM。

binding:一(yī)個對象,包含以下(xià)屬性。

value:傳遞給指令的值。例如(rú)在 v-my-directive="1 + 1" 中,值是 2。

oldValue:之前的值,僅在 beforeUpdate 和(hé) updated 中可(kě)用。無論值是否更改,它都(dōu)可(kě)用。

arg:傳遞給指令的參數(shù) (如(rú)果有的話)。例如(rú)在 v-my-directive:foo 中,參數(shù)是 "foo"。

modifiers:一(yī)個包含修飾符的對象 (如(rú)果有的話)。例如(rú)在 v-my-directive.foo.bar 中,修飾符對象是 { foo: true, bar: true }。

instance:使用該指令的組件實例。

dir:指令的定義對象。

vnode:代表綁定元素的底層 VNode。

prevNode:之前的渲染中代表指令所綁定元素的 VNode。僅在 beforeUpdate 和(hé) updated 鈎子中可(kě)用。

舉例來說,像下(xià)面這(zhè)樣使用指令:

template

<div v-example:foo.bar="baz">

binding 參數(shù)會是一(yī)個這(zhè)樣的對象:

js

{

arg: 'foo',

modifiers: { bar: true },

value: /* `baz` 的值 */,

oldValue: /* 上(shàng)一(yī)次更新時(shí) `baz` 的值 */

}

和(hé)內(nèi)置指令類似,自(zì)定義指令的參數(shù)也可(kě)以是動态的。舉例來說:

template

<div v-example:[arg]="value"></div>

這(zhè)裏指令的參數(shù)會基于組件的 arg 數(shù)據屬性響應式地(dì)更新。

Note

除了(le) el 外(wài),其他(tā)參數(shù)都(dōu)是隻讀的,不要(yào)更改它們。若你需要(yào)在不同的鈎子間(jiān)共享信息,推薦通(tōng)過元素的 dataset attribute 實現。

簡化形式

對于自(zì)定義指令來說,一(yī)個很(hěn)常見(jiàn)的情況是僅僅需要(yào)在 mounted 和(hé) updated 上(shàng)實現相同的行(xíng)為(wèi),除此之外(wài)并不需要(yào)其他(tā)鈎子。這(zhè)種情況下(xià)我們可(kě)以直接用一(yī)個函數(shù)來定義指令,如(rú)下(xià)所示:

template

<div v-color="color"></div>

js

app.directive('color', (el, binding) => {

// 這(zhè)會在 `mounted` 和(hé) `updated` 時(shí)都(dōu)調用

el.style.color = binding.value

})

對象字面量

如(rú)果你的指令需要(yào)多個值,你可(kě)以向它傳遞一(yī)個 JavaScript 對象字面量。别忘了(le),指令也可(kě)以接收任何合法的 JavaScript 表達式。

template

<div v-demo="{ color: 'white', text: 'hello!' }"></div>

js

app.directive('demo', (el, binding) => {

console.log(binding.value.color) // => "white"

console.log(binding.value.text) // => "hello!"

})

在組件上(shàng)使用

當在組件上(shàng)使用自(zì)定義指令時(shí),它會始終應用于組件的根節點,和(hé)透傳 attributes 類似。

template

<MyComponent v-demo="test" />

template

<!-- MyComponent 的模闆 -->

<div> <!-- v-demo 指令會被應用在此處 -->

<span>My component content</span>

</div>

需要(yào)注意的是組件可(kě)能(néng)含有多個根節點。當應用到一(yī)個多根組件時(shí),指令将會被忽略且抛出一(yī)個警告。和(hé) attribute 不同,指令不能(néng)通(tōng)過 v-bind="$attrs" 來傳遞給一(yī)個不同的元素。總的來說,不推薦在組件上(shàng)使用自(zì)定義指令。

網站建設開(kāi)發|APP設計開(kāi)發|小程序建設開(kāi)發
下(xià)一(yī)篇:插件
上(shàng)一(yī)篇:組合式函數(shù)