Vue 3 | 自定義指令的新玩法
開門見山?
按照慣例,從上帝視角看一下自定義指令在 Vue 3 中發(fā)生了哪些改變:
自定義指令的 API 改了名字,名字更貼近組件的生命周期 自定義指令可以通過子組件的? v-bind="$attr"傳遞

Vue2.x 的自定義指令?
在 Vue 2 中,自定義指令通過以下可選的鉤子去創(chuàng)建:
bind:當(dāng)指令綁定在對(duì)應(yīng)元素時(shí)觸發(fā)。只會(huì)觸發(fā)一次。 inserted:當(dāng)對(duì)應(yīng)元素被插入到 DOM 的父元素時(shí)觸發(fā)。 update:當(dāng)元素更新時(shí),這個(gè)鉤子會(huì)被觸發(fā)(此時(shí)元素的后代元素還沒有觸發(fā)更新)。 componentUpdated:當(dāng)整個(gè)組件(包括子組件)完成更新后,這個(gè)鉤子觸發(fā)。 unbind:當(dāng)指令被從元素上移除時(shí),這個(gè)鉤子會(huì)被觸發(fā)。也只觸發(fā)一次。
來看個(gè)例子:
<h1?v-highlight="red">這是一串被高亮為紅色的字h1>
Vue.directive('highlight',?{
??bind(el,?binding,?vnode)?{
????el.style.background?=?binding.value;
??}
});
如上是一個(gè)很靈活的做法,通過指令傳值的做法,可以供開發(fā)者根據(jù)使用場景的不同提供不同的參數(shù),以達(dá)到不同的效果。

Vue 3 的自定義指令?
在 Vue 3 中,官方團(tuán)隊(duì)將自定義指令的 API 打造的更加“被人所熟悉”。正如你馬上會(huì)看到的那樣,盡管它們和組件的生命周期完全是兩回事,但為了更有助于代碼的可讀性和風(fēng)格統(tǒng)一,還是選擇了比較接近的鉤子名稱:
bind =>?beforeMount inserted =>?mounted beforeUpdate: 新的鉤子,會(huì)在元素自身更新前觸發(fā) update =>?移除! componentUpdated =>?updated beforeUnmount: 新的鉤子,當(dāng)元素自身被卸載前觸發(fā) unbind =>?unmounted
所以,新版的自定義指令大概會(huì)長這個(gè)樣子:
const?NewDirective?=?{
??beforeMount(el,?binding,?vnode,?prevVnode)?{},
??mounted()?{},
??beforeUpdate()?{},
??updated()?{},
??beforeUnmount()?{},
??unmounted()?{},
}
吶,上面的那個(gè)例子就會(huì)被改寫成:
const?app?=?Vue.createApp({});
app.directive('highlight',?{
??beforeMount(el,?binding,?vnode)?{
????el.style.background?=?binding.value;
??},
});
改了名字之后,是不是更好記了呢?

細(xì)節(jié),注意細(xì)節(jié)?
Vue 3 是支持 fragments 的,也就是說,我們可以在一個(gè)組件中保留多個(gè)根節(jié)點(diǎn)。
<template>
??<li>你好li>
??<li>我的li>
??<li>粉絲li>
template>
于是自定義指令就遇到了一個(gè)新的問題:自定義指令有多個(gè)根節(jié)點(diǎn)?
因此,現(xiàn)在的自定義指令已經(jīng)是 Virtual DOM 節(jié)點(diǎn)的一部分了。當(dāng)組件上掛載了自定義指令時(shí),它的鉤子會(huì)作為一個(gè)外部屬性傳遞進(jìn)組件內(nèi),最終“落地”于組件的?this.$attr。
這也就意味著,像下面這種直接在元素上掛載生命周期鉤子的寫法,即將同樣適用于自定義指令的鉤子:
<div?@vnodeMounted="myHook">div>
自定義指令向組件內(nèi)傳遞 hook 的行為,和組件樹中自上而下傳遞 prop 的行為是一致的。當(dāng)一個(gè)組件給自身內(nèi)部的元素綁定了?v-bind="$attr"?時(shí),也會(huì)將自身的所有自定義指令都傳遞給自己的子元素。

“?如果想了解更詳細(xì)的信息,請(qǐng)前往:https://v3.vuejs.org/guide/migration/custom-directives.html#overview(目前還沒有中文版)
推薦閱讀
「一個(gè)有溫度的前端號(hào)」
長按識(shí)別二維碼關(guān)注

