做自(zì)由與創造的先行者

自(zì)定義指令

Vue.js中文(wén)手冊

介紹

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

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

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

js

const focus = {

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

}

export default {

directives: {

// 在模闆中啓用(yòng) v-focus

focus

}

}

template

<input v-focus />

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

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

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

js

const app = createApp({})

// 使 v-focus 在所有組件中都可用(yòng)

app.directive('focus', {

/* ... */

})

TIP

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

指令鈎子

一個指令的定義對(duì)象可以提供幾種鈎子函數 (都是可選的):

js

const myDirective = {

// 在綁定元素的 attribute 前

// 或事(shì)件監聽器應用(yòng)前調用(yòng)

created(el, binding, vnode, prevVnode) {

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

},

// 在元素被插入到(dào) DOM 前調用(yòng)

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

// 在綁定元素的父組件

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

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

// 綁定元素的父組件更新前調用(yòng)

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

// 在綁定元素的父組件

// 及他(tā)自(zì)己的所有子節點都更新後調用(yòng)

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

// 綁定元素的父組件卸載前調用(yòng)

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

// 綁定元素的父組件卸載後調用(yòng)

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

}

鈎子參數

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

el:指令綁定到(dào)的元素。這(zhè)可以用(yòng)于直接操作(zuò) DOM。

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

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

oldValue:之前的值,僅在 beforeUpdate 和(hé) updated 中可用(yòng)。無論值是否更改,它都可用(yòng)。

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

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

instance:使用(yòng)該指令的組件實例。

dir:指令的定義對(duì)象。

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

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

舉例來(lái)說,像下(xià)面這(zhè)樣使用(yòng)指令:

template

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

binding 參數會(huì)是一個這(zhè)樣的對(duì)象:

js

{

arg: 'foo',

modifiers: { bar: true },

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

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

}

和(hé)内置指令類似,自(zì)定義指令的參數也(yě)可以是動态的。舉例來(lái)說:

template

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

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

Note

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

簡化形式

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

template

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

js

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

// 這(zhè)會(huì)在 `mounted` 和(hé) `updated` 時(shí)都調用(yòng)

el.style.color = binding.value

})

對(duì)象字面量

如果你(nǐ)的指令需要多個值,你(nǐ)可以向它傳遞一個 JavaScript 對(duì)象字面量。别忘了(le),指令也(yě)可以接收任何合法的 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)使用(yòng)

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

template

<MyComponent v-demo="test" />

template

<!-- MyComponent 的模闆 -->

<div> <!-- v-demo 指令會(huì)被應用(yòng)在此處 -->

<span>My component content</span>

</div>

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

網站(zhàn)建設開(kāi)發|APP設計(jì)開(kāi)發|小(xiǎo)程序建設開(kāi)發
下(xià)一篇:插件
上(shàng)一篇:組合式函數