Dyrektywy niestandardowe
Wprowadzenie
Oprócz domyślnego zestawu dyrektyw dostarczanych w rdzeniu (takich jak v-model
lub v-show
), Vue pozwala również na rejestrowanie własnych dyrektyw niestandardowych.
Wprowadziliśmy dwie formy ponownego wykorzystania kodu w Vue: komponenty i funkcje kompozycyjne. Komponenty są głównymi blokami konstrukcyjnymi, podczas gdy funkcje kompozycyjne koncentrują się na ponownym wykorzystaniu logiki stanowej. Z drugiej strony dyrektywy niestandardowe są przeznaczone głównie do ponownego wykorzystania logiki, która obejmuje dostęp do DOM niskiego poziomu w zwykłych elementach.
Dyrektywa niestandardowa jest zdefiniowana jako obiekt zawierający haki cyklu życia podobne do haków komponentu. Haki otrzymują element, do którego dyrektywa jest powiązana. Oto przykład dyrektywy, która skupia dane wejściowe, gdy element jest wstawiany do DOM przez Vue:
vue
<script setup>
// włącza v-focus w szablonach
const vFocus = {
mounted: (el) => el.focus()
}
</script>
<template>
<input v-focus />
</template>
Zakładając, że nie kliknąłeś nigdzie indziej na stronie, powyższe dane wejściowe powinny być automatycznie wyostrzone. Ta dyrektywa jest bardziej użyteczna niż atrybut autofocus
, ponieważ działa nie tylko podczas ładowania strony - działa również, gdy element jest dynamicznie wstawiany przez Vue.
W <script setup>
, każda zmienna camelCase zaczynająca się od prefiksu v
może być używana jako dyrektywa niestandardowa. W powyższym przykładzie vFocus
może być używana w szablonie jako v-focus
.
Jeśli nie używasz <script setup>
, dyrektywy niestandardowe można zarejestrować za pomocą opcji directives
:
js
export default {
setup() {
/*...*/
},
directives: {
// włącza v-focus w szablonach
focus: {
/* ... */
}
}
}
Powszechną praktyką jest również globalne rejestrowanie dyrektyw niestandardowych na poziomie aplikacji:
js
const app = createApp({})
// spraw, aby v-focus był używalny we wszystkich komponentach or umożliw używanie v-focus we wszystkich komponentach
app.directive('focus', {
/* ... */
})
TIP
W miarę możliwości należy preferować deklaratywne tworzenie szablonów przy użyciu wbudowanych dyrektyw, takich jak v-bind
, ponieważ są one bardziej wydajne i przyjazne dla renderowania po stronie serwera.
Cykle życia dyrektyw
Obiekt definicji dyrektywy może zapewniać kilka funkcji hookowych (wszystkie opcjonalne):
js
const myDirective = {
// wywoływane przed atrybutami powiązanego elementu
// lub zastosowaniem nasłuchiwaczy zdarzeń
created(el, binding, vnode) {
// zobacz poniżej szczegóły dotyczące argumentów
},
// wywoływana tuż przed umieszczeniem elementu do DOM.
beforeMount(el, binding, vnode) {},
// wywoływane, gdy komponent nadrzędny powiązanego elementu
// i wszystkie jego elementy podrzędne są zamontowane.
mounted(el, binding, vnode) {},
// wywoływane przed aktualizacją komponentu nadrzędnego
beforeUpdate(el, binding, vnode, prevVnode) {},
// wywoływane po tym, jak komponent nadrzędny i
// wszystkie jego komponenty podrzędne zostały zaktualizowane
updated(el, binding, vnode, prevVnode) {},
// wywoływane przed odmontowaniem komponentu nadrzędnego
beforeUnmount(el, binding, vnode) {},
// wywoływane, gdy komponent nadrzędny jest odmontowany
unmounted(el, binding, vnode) {}
}
Argumenty cyklów zycia dyrektyw
Do hooków dyrektyw przekazywane są następujące argumenty:
el
: element, do którego dyrektywa jest przypisana. Może być używany do bezpośredniej manipulacji DOM.binding
: obiekt zawierający następujące właściwości.value
: wartość przekazana do dyrektywy. Na przykład wv-my-directive="1 + 1"
, wartością byłoby2
.oldValue
: poprzednia wartość, dostępna tylko wbeforeUpdate
iupdated
. Jest dostępna niezależnie od tego, czy wartość została zmieniona.arg
: argument przekazany do dyrektywy, jeśli taki istnieje. Na przykład wv-my-directive:foo
, argumentem byłoby"foo"
.modifiers
: obiekt zawierający modyfikatory, jeśli takie istnieją. Na przykład wv-my-directive.foo.bar
, obiektem modyfikatorów byłby{ foo: true, bar: true }
.instance
: Instancja komponentu, w którym użyto dyrektywy.dir
: obiekt definicji dyrektywy.vnode
: bazowy VNode reprezentujący powiązany element.prevVnode
: VNode reprezentujący powiązany element z poprzedniego renderowania. Dostępne tylko w hakachbeforeUpdate
iupdated
.
Jako przykład rozważmy następujące użycie dyrektywy:
template
<div v-example:foo.bar="baz">
Argument binding
będzie obiektem o kształcie:
js
{
arg: 'foo',
modifiers: { bar: true },
value: /* wartość `baz` */,
oldValue: /* wartość `baz` z poprzedniej aktualizacji */
}
Podobnie jak wbudowane dyrektywy, argumenty dyrektyw niestandardowych mogą być dynamiczne. Na przykład:
template
<div v-example:[arg]="value"></div>
Tutaj argument dyrektywy zostanie reaktywnie zaktualizowany na podstawie właściwości arg
w stanie naszego komponentu.
Note
Oprócz el
, powinieneś traktować te argumenty jako tylko do odczytu i nigdy ich nie modyfikować. Jeśli musisz udostępniać informacje między hakami, zaleca się, aby zrobić to za pośrednictwem elementu dataset.
Skrócone funkcje
Często zdarza się, że dyrektywa niestandardowa zachowuje się tak samo dla mounted
i updated
, bez potrzeby innych haków. W takich przypadkach możemy zdefiniować dyrektywę jako funkcję:
template
<div v-color="color"></div>
js
app.directive('color', (el, binding) => {
// to będzie wywoływane zarówno dla `mounted` jak i `updated`
el.style.color = binding.value
})
Obiekty literalne
Jeśli Twoja dyrektywa wymaga wielu wartości, możesz również przekazać obiekt JavaScript literal. Pamiętaj, że dyrektywy mogą przyjmować dowolne prawidłowe wyrażenie JavaScript.
template
<div v-demo="{ color: 'biały', text: 'Hej!' }"></div>
js
app.directive('demo', (el, binding) => {
console.log(binding.value.color) // => "biały"
console.log(binding.value.text) // => "Hej!"
})
Użycie na komponentach
Not recommended
Nie zaleca się używania dyrektyw niestandardowych w komponentach. Nieoczekiwane zachowanie może wystąpić, gdy komponent ma wiele węzłów głównych.
Gdy są używane w komponentach, dyrektywy niestandardowe zawsze będą miały zastosowanie do węzła głównego komponentu, podobnie jak Fallthrough Attributes.
template
<MyComponent v-demo="test" />
template
<!-- template of MyComponent -->
<div> <!-- dyrektywa v-demo będzie tutaj dodana -->
<span>Zawartość mojego komponentu</span>
</div>
Należy pamiętać, że komponenty mogą potencjalnie mieć więcej niż jeden węzeł główny. Po zastosowaniu w komponencie posiadającym więcej niż jeden węzeł główny dyrektywa zostanie zignorowana i zostanie wygenerowane ostrzeżenie. W przeciwieństwie do atrybutów, dyrektyw nie można przekazać do innego elementu za pomocą v-bind="$attrs"
.