Vlastní direktivy
Úvod
Kromě výchozí sady vestavěných direktiv (jako je v-model
nebo v-show
) umožňuje Vue také registraci vašich vlastních (custom) direktiv.
Ve Vue jsme zavedli dvě formy znovupoužitelného kódu: komponenty a composables. Komponenty jsou hlavními stavebními bloky, zatímco composables se zaměřují na znovupoužití stavové logiky. Vlastní direktivy jsou naproti tomu určeny hlavně ke znovupoužití logiky, která se týká low-level přístupu k DOM na prostých elementech.
Vlastní direktiva je definována jako objekt obsahující lifecycle hooks podobné těm, které má komponenta. Hook obdrží element, na který je direktiva navázána. Zde je příklad direktivy, která elementu přidá třídu, když je vložen do DOM pomocí Vue:
vue
<script setup>
// umožní v šablonách v-highlight
const vHighlight = {
mounted: (el) => {
el.classList.add('is-highlight')
}
}
</script>
<template>
<p v-highlight>Tato věta je důležitá!</p>
</template>
Tato věta je důležitá!
Ve <script setup>
lze jako vlastní direktivu použít jakoukoli proměnnou zapsanou v camelCase tvaru, která začíná předponou v
. Ve výše uvedeném příkladu lze vHighlight
použít v šabloně jako v-highlight
.
Pokud nepoužíváte <script setup>
, lze vlastní direktivy registrovat pomocí možnosti directives
:
js
export default {
setup() {
/*...*/
},
directives: {
// umožní v šablonách v-highlight
highlight: {
/* ... */
}
}
}
Běžné je i registrovat vlastní direktivy globálně na úrovni aplikace:
js
const app = createApp({})
// v-highlight bude použitelný ve všech komponentách
app.directive('highlight', {
/* ... */
})
Kdy vlastní direktivy používat
Vlastní direktivy by se měly používat pouze v případě, že požadované funkcionality lze dosáhnout pouze přímou manipulací s DOM.
Běžným příkladem je direktiva v-focus
, která přináší focus na daný element.
vue
<script setup>
// umožní v šablonách v-focus
const vFocus = {
mounted: (el) => el.focus()
}
</script>
<template>
<input v-focus />
</template>
Tato direktiva je užitečnější než atribut autofocus
, protože funguje nejen při načítání stránky - funguje i tehdy, když je prvek vkládán dynamicky pomocí Vue!
Pokud je to však možné, je doporučeno dávat přednost deklarativnímu použití šablon pomocí vestavěných direktiv, jako je v-bind
, protože jsou efektivnější a šetrnější k vykreslování na serveru.
Lifecycle Hooks direktiv
Objekt definice direktivy může poskytovat několik „hook“ funkcí (všechny jsou nepovinné):
js
const mojeDirektiva = {
// volána před aplikací
// navázaných atributů elementů či event listenerů
created(el, binding, vnode) {
// detaily jednotlivých parametrů viz níže
},
// volána těsně před vložením elementu do DOM
beforeMount(el, binding, vnode) {},
// volána po `mounted` (vložení do DOM)
// na komponentě rodiče a všech jejích potomcích
mounted(el, binding, vnode) {},
// volána před `updated` na komponentě rodiče
beforeUpdate(el, binding, vnode, prevVnode) {},
// volána po `updated` na komponentě rodiče
// a všech jejích potomcích
updated(el, binding, vnode, prevVnode) {},
// volána před `unmounted` na komponentě rodiče
beforeUnmount(el, binding, vnode) {},
// volána po `unmounted` na komponentě rodiče
unmounted(el, binding, vnode) {}
}
Parametry lifecycle hooks direktiv
Hooks direktiv obdrží tyto parametry:
el
: Prvek, na který je direktiva navázána. Lze jej použít k přímé manipulaci s DOM.binding
: Objekt, který obsahuje následující vlastnosti:value
: Hodnota předávaná do direktivy. Například prov-my-directive="1 + 1"
bude hodnota2
.oldValue
: Předchozí hodnota. Dostupná pouze vbeforeUpdate
aupdated
. Je dostupná, ať už se hodnota změnila nebo ne.arg
: Parametr předávaný do direktivy, pokud existuje. Například prov-my-directive:foo
bude parametr"foo"
.modifiers
: Objekt, který obsahuje modifikátory, pokud jsou nastaveny. Například prov-my-directive.foo.bar
bude objekt modifikátorů{ foo: true, bar: true }
.instance
: Instance komponent, ve které je direktiva použita.dir
: Objekt definice direktivy
vnode
: VNode objekt, který představuje navázaný element.prevVnode
: VNode objekt, který představoval navázaný element při předchozím vykreslení. Dostupný pouze vbeforeUpdate
aupdated
.
Jako příklad uvažte následující použití direktivy:
template
<div v-example:foo.bar="baz">
Parametr binding
bude objekt ve tvaru:
js
{
arg: 'foo',
modifiers: { bar: true },
value: /* hodnota `baz` */,
oldValue: /* hodnota `baz` z předchozího `update` */
}
Podobně jako vestavěné direktivy mohou být parametry vlastních direktiv dynamické. Například:
template
<div v-example:[arg]="value"></div>
Zde bude parametr direktivy reaktivně aktualizován na základě vlastnosti arg
ze stavu naší komponenty.
Poznámka
Kromě el
byste s těmito parametry měli zacházet jako s read-only hodnotami a nikdy je neměnit. Pokud potřebujete sdílet informace napříč hooks, doporučujeme to dělat prostřednictvím atributu dataset.
Zkrácený zápis funkcí
Pro vlastní direktivy je běžné, že mají stejné chování pro mounted
i updated
a nepotřebují další hooks. V takových případech můžeme direktivu definovat jako funkci:
template
<div v-color="color"></div>
js
app.directive('color', (el, binding) => {
// toto bude zavoláno pro `mounted` i `updated`
el.style.color = binding.value
})
Object Literals
Pokud vaše direktiva potřebuje více hodnot, můžete předat také JavaScript object literal. Vzpomeňte, že direktivy mohou přebírat libovolný platný JavaScript výraz.
template
<div v-demo="{ color: 'bílá', text: 'Ahoj!' }"></div>
js
app.directive('demo', (el, binding) => {
console.log(binding.value.color) // => "bílá"
console.log(binding.value.text) // => "Ahoj!"
})
Použití na komponenty
Nedoporučeno
Použití vlastních direktiv na komponenty není doporučeno. Pokud má komponenta více než jeden root element, může mít použití direktivy neočekávané výsledky.
Při použití na komponenty se vlastní direktivy vždy vztahují na root element komponenty, podobně jako u Fallthrough atributů.
template
<MyComponent v-demo="test" />
template
<!-- šablona MyComponent -->
<div> <!-- direktiva v-demo bude aplikována zde -->
<span>Obsah mé komponenty</span>
</div>
Pamatujte, že komponenty mohou mít potenciálně více než jeden root element. Při použití na multi-root komponentu bude direktiva ignorována a bude vypsáno varování. Na rozdíl od atributů předat direktivy jinému elementu pomocí v-bind="$attrs"
nelze.