Directives personnalisées
Introduction
En plus du jeu de directives par défaut fourni par Vue (comme v-model
ou v-show
), Vue permet également d'enregistrer vos propres directives personnalisées.
Nous avons introduit deux formes de code réutilisable dans Vue : les composants et les composables. Les composants sont les principaux éléments de construction, alors que les composables sont axés sur la réutilisation de la logique d'état. Les directives personnalisées, quant à elles, sont principalement destinées à réutiliser la logique qui implique un accès de bas niveau au DOM sur des éléments simples.
Une directive personnalisée se définit comme un objet contenant des hooks du cycle de vie, similaires à ceux d'un composant. Les hooks reçoivent l'élément auquel la directive est liée. Voici un exemple d'une directive qui met le focus sur un champ de saisie lorsque l'élément est inséré dans le DOM par Vue :
vue
<script setup>
// active v-focus dans les templates
const vFocus = {
mounted: (el) => el.focus()
}
</script>
<template>
<input v-focus />
</template>
En supposant que vous n'ayez pas cliqué ailleurs sur la page, le champ de saisie ci-dessus devrait être auto-focalisé. Cette directive est plus utile que l'attribut autofocus
car elle ne fonctionne pas uniquement au chargement de la page - elle fonctionne également lorsque l'élément est inséré dynamiquement par Vue.
Dans <script setup>
, toute variable camelCase qui commence par le préfixe v
peut être utilisée comme une directive personnalisée. Dans l'exemple ci-dessus, vFocus
peut être utilisé dans le template via v-focus
.
Si vous n'utilisez pas <script setup>
, les directives personnalisées peuvent être enregistrées grâce à l'option directives
:
js
export default {
setup() {
/*...*/
},
directives: {
// active v-focus dans le template
focus: {
/* ... */
}
}
}
It is also common to globally register custom directives at the app level:
js
const app = createApp({})
// make v-focus usable in all components
app.directive('focus', {
/* ... */
})
TIP
Les directives personnalisées ne doivent être utilisées que lorsque la fonctionnalité souhaitée ne peut être obtenue seulement par une manipulation directe du DOM. Préférez les templates déclaratifs utilisant des directives intégrées telles que v-bind
lorsque c'est possible, car ils sont plus efficaces et respectueux du rendu côté serveur.
Hooks des directives
La définition d'un objet directive peut fournir plusieurs fonctions de hook (toutes optionnelles) :
js
const myDirective = {
// appelé avant les attributs de l'élément lié
// ou que les écouteurs d'événements soient appliqués
created(el, binding, vnode, prevVnode) {
// voir ci-dessous pour plus de détails sur les arguments
},
// appelé juste avant que l'élément ne soit inséré dans le DOM.
beforeMount(el, binding, vnode, prevVnode) {},
// appelé lorsque le composant parent de l'élément lié
// et tous ses enfants soient montés.
mounted(el, binding, vnode, prevVnode) {},
// appelé avant que le composant parent ne soit mis à jour
beforeUpdate(el, binding, vnode, prevVnode) {},
// appelé après que le composant parent et
// tous ses enfants aient été mis à jour
updated(el, binding, vnode, prevVnode) {},
// appelé avant que le composant parent ne soit démonté
beforeUnmount(el, binding, vnode, prevVnode) {},
// appelé lorsque le composant parent est démonté
unmounted(el, binding, vnode, prevVnode) {}
}
Arguments d'un hook
Les hooks des directives fournissent ces différents arguments :
el
: l'élément auquel la directive est liée. Il peut être utilisé pour manipuler le DOM directement.binding
: un objet contenant les propriétés suivantes.value
: La valeur transmise à la directive. Par exemple, dansv-my-directive="1 + 1"
, la valeur sera2
.oldValue
: La valeur précédente, disponible uniquement dansbeforeUpdate
etupdated
. Elle est disponible que la valeur ait changé ou non.arg
: L'argument passé à la directive, s'il y en a un. Par exemple, dansv-my-directive:foo
, l'argument sera"foo"
.modifiers
: Un objet contenant des modificateurs, s'il y en a. Par exemple, dansv-my-directive.foo.bar
, l'objet modificateur sera{ foo : true, bar : true }
.instance
: L'instance du composant où la directive est utilisée.dir
: l'objet de définition de la directive.
vnode
: le VNode sous-jacent représentant l'élément lié.prevNode
: le VNode représentant l'élément lié du rendu précédent. Disponible uniquement dans les hooksbeforeUpdate
etupdated
.
En guise d'exemple, considérez l'utilisation de la directive suivante :
template
<div v-example:foo.bar="baz">
L'argument binding
serait un objet de la forme de :
js
{
arg: 'foo',
modifiers: { bar: true },
value: /* valeur de `baz` */,
oldValue: /* valeur de `baz` de la mise à jour précédente */
}
De la même manière que pour les directives natives, les arguments des directives personnalisées peuvent être dynamiques. Par exemple :
template
<div v-example:[arg]="value"></div>
Ici, l'argument de la directive sera mis à jour de manière réactive en fonction de la propriété arg
dans l'état de notre composant.
Remarque
En dehors de el
, vous devez traiter ces arguments comme étant en lecture seule et ne jamais les modifier. Si vous devez partager des informations entre plusieurs hooks, il est recommandé de le faire par le biais de dataset de l'élément.
Abréviations de fonctions
Il est courant qu'une directive personnalisée ait le même comportement pour mounted
et updated
, sans avoir besoin des autres hooks. Dans ce cas, nous pouvons définir la directive comme une fonction :
template
<div v-color="color"></div>
js
app.directive('color', (el, binding) => {
// sera appelée à la fois au `mounted` et au `updated`
el.style.color = binding.value
})
Littéraux d'un objet
Si votre directive a besoin de plusieurs valeurs, vous pouvez également lui passer un objet JavaScript littéral. Souvenez-vous, les directives peuvent prendre n'importe quelle expression JavaScript valide.
template
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
js
app.directive('demo', (el, binding) => {
console.log(binding.value.color) // => "blanc"
console.log(binding.value.text) // => "bonjour!"
})
Utilisation sur les composants
Lorsqu'elles sont utilisées sur des composants, les directives personnalisées s'appliquent toujours au nœud racine du composant, comme dans les attributs implicitement déclarés.
template
<MyComponent v-demo="test" />
template
<!-- template de MyComponent -->
<div> <!-- la directive v-demo sera appliquée ici -->
<span>My component content</span>
</div>
Notez que les composants peuvent potentiellement avoir plus d'un nœud racine. Lorsqu'elle est appliquée à un composant multi-racine, une directive sera ignorée et un avertissement sera envoyé. Contrairement aux attributs, les directives ne peuvent pas être passées à un autre élément avec v-bind="$attrs"
. En général, il n'est pas recommandé d'utiliser des directives personnalisées sur des composants.