W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
除了核心功能默認(rèn)內(nèi)置的指令 (v-model
和 v-show
),Vue 也允許注冊自定義指令。注意,在 Vue2.0 中,代碼復(fù)用和抽象的主要形式是組件。然而,有的情況下,你仍然需要對普通 DOM 元素進(jìn)行底層操作,這時(shí)候就會用到自定義指令。舉個(gè)聚焦輸入框的例子,如下:
當(dāng)頁面加載時(shí),該元素將獲得焦點(diǎn) (注意:autofocus
在移動(dòng)版 Safari 上不工作)。事實(shí)上,只要你在打開這個(gè)頁面后還沒點(diǎn)擊過任何內(nèi)容,這個(gè)輸入框就應(yīng)當(dāng)還是處于聚焦?fàn)顟B(tài)。此外,你可以單擊 Rerun
按鈕,輸入將被聚焦。
現(xiàn)在讓我們用指令來實(shí)現(xiàn)這個(gè)功能:
const app = Vue.createApp({})
// 注冊一個(gè)全局自定義指令 `v-focus`
app.directive('focus', {
// 當(dāng)被綁定的元素插入到 DOM 中時(shí)……
mounted(el) {
// Focus the element
el.focus()
}
})
如果想注冊局部指令,組件中也接受一個(gè) directives
的選項(xiàng):
directives: {
focus: {
// 指令的定義
mounted(el) {
el.focus()
}
}
}
然后你可以在模板中任何元素上使用新的 v-focus
property,如下:
<input v-focus />
一個(gè)指令定義對象可以提供如下幾個(gè)鉤子函數(shù) (均為可選):
beforeMount
:當(dāng)指令第一次綁定到元素并且在掛載父組件之前調(diào)用。在這里你可以做一次性的初始化設(shè)置。mounted
:在掛載綁定元素的父組件時(shí)調(diào)用。beforeUpdate
:在更新包含組件的 VNode 之前調(diào)用。提示
我們會在稍后討論渲染函數(shù)時(shí)介紹更多 VNodes 的細(xì)節(jié)。
updated
:在包含組件的 VNode 及其子組件的 VNode 更新后調(diào)用。beforeUnmount
:在卸載綁定元素的父組件之前調(diào)用unmounted
:當(dāng)指令與元素解除綁定且父組件已卸載時(shí),只調(diào)用一次。
接下來我們來看一下在自定義指令 API 鉤子函數(shù)的參數(shù) (即 el
、binding
、vnode
和 prevNnode
)
指令的參數(shù)可以是動(dòng)態(tài)的。例如,在 v-mydirective:[argument]="value"
中,argument
參數(shù)可以根據(jù)組件實(shí)例數(shù)據(jù)進(jìn)行更新!這使得自定義指令可以在應(yīng)用中被靈活使用。
例如你想要?jiǎng)?chuàng)建一個(gè)自定義指令,用來通過固定布局將元素固定在頁面上。我們可以像這樣創(chuàng)建一個(gè)通過指令值來更新豎直位置像素值的自定義指令:
<div id="dynamic-arguments-example" class="demo">
<p>Scroll down the page</p>
<p v-pin="200">Stick me 200px from the top of the page</p>
</div>
const app = Vue.createApp({})
app.directive('pin', {
mounted(el, binding) {
el.style.position = 'fixed'
// binding.value is the value we pass to directive - in this case, it's 200
el.style.top = binding.value + 'px'
}
})
app.mount('#dynamic-arguments-example')
這會把該元素固定在距離頁面頂部 200 像素的位置。但如果場景是我們需要把元素固定在左側(cè)而不是頂部又該怎么辦呢?這時(shí)使用動(dòng)態(tài)參數(shù)就可以非常方便地根據(jù)每個(gè)組件實(shí)例來進(jìn)行更新。
<div id="dynamicexample">
<h3>Scroll down inside this section ↓</h3>
<p v-pin:[direction]="200">I am pinned onto the page at 200px to the left.</p>
</div>
const app = Vue.createApp({
data() {
return {
direction: 'right'
}
}
})
app.directive('pin', {
mounted(el, binding) {
el.style.position = 'fixed'
// binding.arg is an argument we pass to directive
const s = binding.arg || 'top'
el.style[s] = binding.value + 'px'
}
})
app.mount('#dynamic-arguments-example')
結(jié)果:
我們的定制指令現(xiàn)在已經(jīng)足夠靈活,可以支持一些不同的用例。為了使其更具動(dòng)態(tài)性,我們還可以允許修改綁定值。讓我們創(chuàng)建一個(gè)附加屬性 pinPadding
,并將其綁定到 <input type="range">
。
<div id="dynamicexample">
<h2>Scroll down the page</h2>
<input type="range" min="0" max="500" v-model="pinPadding">
<p v-pin:[direction]="pinPadding">Stick me {{ pinPadding + 'px' }} from the {{ direction }} of the page</p>
</div>
const app = Vue.createApp({
data() {
return {
direction: 'right',
pinPadding: 200
}
}
})
讓我們擴(kuò)展我們的指令邏輯來重新計(jì)算固定元件更新的距離。
app.directive('pin', {
mounted(el, binding) {
el.style.position = 'fixed'
const s = binding.arg || 'top'
el.style[s] = binding.value + 'px'
},
updated(el, binding) {
const s = binding.arg || 'top'
el.style[s] = binding.value + 'px'
}
})
結(jié)果:
在很多時(shí)候,你可能想在 mounted
和 updated
時(shí)觸發(fā)相同行為,而不關(guān)心其它的鉤子。比如這樣寫:
app.directive('pin', (el, binding) => {
el.style.position = 'fixed'
const s = binding.arg || 'top'
el.style[s] = binding.value + 'px'
})
如果指令需要多個(gè)值,可以傳入一個(gè) JavaScript 對象字面量。記住,指令函數(shù)能夠接受所有合法的 JavaScript 表達(dá)式。
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
app.directive('demo', (el, binding) => {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "hello!"
})
在 3.0 中,有了片段支持,組件可能有多個(gè)根節(jié)點(diǎn)。如果在具有多個(gè)根節(jié)點(diǎn)的組件上使用自定義指令,則會產(chǎn)生問題。
要解釋自定義指令如何在 3.0 中的組件上工作的詳細(xì)信息,我們首先需要了解自定義指令在 3.0 中是如何編譯的。對于這樣的指令:
<div v-demo="test"></div>
將大概編譯成:
const vDemo = resolveDirective('demo')
return withDirectives(h('div'), [[vDemo, test]])
其中 vDemo
是用戶編寫的指令對象,其中包含 mounted
和 updated
等鉤子。
withDirectives
返回一個(gè)克隆的 VNode,其中用戶鉤子被包裝并作為 VNode 生命周期鉤子注入 (請參見渲染函數(shù)更多詳情):
{
onVnodeMounted(vnode) {
// call vDemo.mounted(...)
}
}
因此,自定義指令作為 VNode 數(shù)據(jù)的一部分完全包含在內(nèi)。當(dāng)在組件上使用自定義指令時(shí),這些 onVnodeXXX
鉤子作為無關(guān)的 prop 傳遞給組件,并以 this.$attrs
結(jié)束。
這也意味著可以像這樣在模板中直接掛接到元素的生命周期中,這在涉及到自定義指令時(shí)非常方便:
<div @vnodeMounted="myHook" />
這和 非 prop 的 attribute類似。因此,組件上自定義指令的規(guī)則將與其他無關(guān) attribute 相同:由子組件決定在哪里以及是否應(yīng)用它。當(dāng)子組件在內(nèi)部元素上使用 v-bind="$attrs"
時(shí),它也將應(yīng)用對其使用的任何自定義指令。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: