Appearance
5. Directives & DOM virtuel
Présentation
Les directives définissent un certain nombre d’opérations logiques qu’il est possible de demander à Vue.js d’effectuer lors de la compilation du template d’un composant. Elles sont intimement liées à la définition de DOM virtuel et de DOM réel.
Dans ce chapitre, nous détaillerons le fonctionnement des principales directives de Vue.js et expliciterons les concepts de DOM réel et virtuel.
DOM virtuel & DOM réel
TIP
📌 Si vous n’êtes pas à l’aise avec le concept de DOM tel qu’il est communément défini en Javascript, allez consulter cet annexe de cours.
Dans les chapitres précédents, nous avons vu que Vue.js était capable de modifier à la volée des éléments HTML d’un composant lorsqu’une donnée était modifiée. Nous savons également qu’il nous est possible d’injecter un certain nombre de variables dans la partie template de nos composants. Tout cela est rendu possible grâce à la notion de DOM virtuel.
Le DOM virtuel représente conceptuellement la vision que nous avons de notre DOM telle que représentée dans la partie template de nos composants. Typiquement, les inclusions de variables sont des éléments constitutifs de notre DOM virtuel, dans le sens où ils ne seraient pas interprétables s’ils faisaient partie d’un document HTML classique.
Par distinction, le DOM réel renvoie quant à lui au DOM tel qu’il est perçu par le navigateur web, chargé d’afficher notre site. A ce niveau, le DOM ne présente que des éléments communément interprétables par le navigateur, plus aucune variable ou élément propre au framework Vue.js n’est présent.
A la création d’un composant, durant la phase de montage (entre beforeMount et mounted), Vue.js va résoudre l’ensemble des éléments virtuels du DOM, comme les variables et les directives, pour ensuite ordonner en Javascript au navigateur la création des objets HTML dans le DOM de la page courante. C’est ce qu’on appelle le rendu du composant.
Si les données du composant sont modifiées, Vue.js amorcera un processus similaire pour modifier en Javascript les parties du DOM réel impactées par le changement apparu dans le DOM virtuel.
REMARQUE
📌 Vue.js ne re-rend bien sûr pas l’ensemble d’un composant à chaque modification. Un certain nombre d’optimisations sont effectuées par Vue.js pour modifier seulement les parties du DOM réel impactées par les changements et ainsi préserver au mieux les performances de l’application.
Il est important de garder en tête cette distinction entre DOM virtuel et réel, en particulier lorsque l’on souhaite effectuer des modifications dans l’un ou l’autre des DOM, comme nous le verrons plus en détail dans la prochaine partie du cours.
Les directives
Les directives prennent la forme d’attributs dans les balises du DOM virtuel. Il peut s’agir d’attributs complètement nouveaux, ou d’attributs transformant le comportement d’attributs déjà existants dans le DOM réel.
v-show
Cette directive vous permet d’énoncer une condition sur une balise qui, si la condition n’est pas remplie, ne sera pas visible dans l’application :
jsx
<template>
<div>
<p v-show="isVisible == true">invisible paragraph</p>
<p>visible paragraph</p>
<div>
</template>
<script>
export default {
...
data() {
return {
isVisible: false
}
}
}
</script>L’attribut v-show n’affichera pas l’élément si sa valeur est false, "", NaN, undefined, null ou 0 . On pourrait ici réduire la syntaxe à v-show="isVisible" .
REMARQUE
👉 Si l’on veut que la balise soit invisible uniquement si la variable vaut true, il faut écrire : v-show="isVisible === true"
On peut également attendre la valeur retournée par une méthode spécifique : v-show=”myMethod()”. Notez toutefois que la fonction ne sera exécutée qu’une seule fois, à l’initialisation du composant. Si une donnée est changée, la méthode ne sera pas rappelée, même si le changement impacte sa valeur de retour.
v-if
Cette directive ressemble beaucoup à v-show. Elle s’utilise de façon similaire :
jsx
<template>
<div>
<p v-if="exist">doesn't exist</p>
<p>exist</p>
<div>
</template>
<script>
export default {
...,
data() {
return {
exist: false
}
}
}
</script>A la différence de v-show qui se contente de rendre le composant invisible, v-if retire complètement la balise du DOM réel. L’ensemble des évènements et logiques présents dans la balise n’existera donc pas.
v-if offre une meilleure performance de l’application en éliminant entièrement le composant du DOM réel. Toutefois, la directive est plus couteuse lors de la permutation : si la valeur de v-if change, cela demandera plus de performance pour créer ou détruire la balise que pour la directive v-show qui se contente de cacher ou afficher la balise.
INFO
💡 Exemple : Imaginons que vous avez un composant qui contient un compteur affichant le temps en seconde depuis sa création. Vous appliquez sur ce composant une directive v-if ou v-show valant initialement false. Après un certain temps, vous passer votre directive à la valeur true. Dans le cas de v-if, votre compteur repartira de zéro. Avec v-show toutefois, votre composant affichera bien le temps écoulé depuis votre arrivée sur la page.
v-else et v-else-if
Ces deux directives permettent d’avoir des logiques conditionnelles plus élaborées. Elles doivent obligatoirement être appelés à la suite d’une directive v-if :
jsx
<template>
<div>
<p v-if="exist">doesn't exist</p>
<p>other</p>
<p v-else-if="exist2">exist</p>
<p v-else>doesn't exist</p>
<div>
</template>
<script>
export default {
...,
data() {
return {
exist: false,
exist2: true
}
}
}
</script>Bien évidemment, la directive v-else n’attend pas de valeur.
v-for
Liste de valeurs primitives
Particulièrement utilisée, cette directive permet de répéter la création d’une balise pour chaque élément présent dans une liste donnée. Il vous est alors possible à l’intérieur de la balise avec la directive de vous référer à l’élément courant de votre liste :
jsx
<template>
<div>
<div v-for="text in texts">
<p>{{ text }}</p>
</div>
<div>
</template>
<script>
export default {
...,
data() {
return {
texts: ["Hello", "World"]
}
}
}
</script>Ce code génèrera donc un bloc avec deux balises p, l’une contenant le texte “Hello” et l’autre “World”.
Vous pouvez également récupérer l’index courant dans votre liste avec : <p v-for="(text, index) in texts"> . Vous pouvez aussi remplacer le mot-clé in par of si vous préférez : <p v-for="text of texts">.
Liste d’objets
Vous pouvez bien sûr utiliser cette directive pour itérer sur une liste d’objets. Vous devrez alors ajouter l’attribut :key sur la balise concernée. Vous indiquerez en valeur de cet attribut un champ détenu par tous les objets parcourus et dont la valeur est unique pour chaque objet :
jsx
<template>
<div>
<ul>
<li v-for="user in users" :key="user.id">
{{ user.firstname }} - {{ user.lastname }}
</li>
</ul>
<div>
</template>
<script>
export default {
...,
data() {
return {
users: [
{ id: 0, firstname:"John", lastname:"Doe" }
{ id: 1, firstname:"Martin", lastname:"Dupont" }
]
}
}
}
</script>WARNING
⚠️ Le champ servant de key doit toujours contenir une valeur primitive, et non un tableau ou un objet.
Pour comprendre le rôle de l’attribut :key, rappelez-vous que Vue.js lie dynamiquement votre directive pour répercuter à la volée les changement de vos données. Par conséquent, si vous changer l’ordre ou le contenu de votre liste dans la donnée users ici par exemple, alors le changement sera immédiatement répercuté sur les éléments de votre DOM réel.
:key permet à Vue de plus simplement identifier les éléments présents dans votre liste afin de plus facilement les réordonner au sein du DOM si nécessaire. Sans lui, il serait contraint de comparer l’entièreté des champs de chaque objet pour correctement les réordonner.
v-bind
Cas général
Cette directive nous permet d’utiliser un attribut déjà existant dans le DOM réel mais en le liant dynamiquement à des éléments du DOM virtuel.
Nous avons déjà utilisé cette directive dans un chapitre précédent lorsque nous avons fait : <img v-bind:src="pictureUrl"/> , où pictureUrl était une props de notre composant.
L’attribut src existe déjà en HTML. Si nous l’utilisons dans notre template, Vue.js se contentera de recopier l’attribut dans le DOM réel, sans chercher à l’interpréter. L’ajout de la directive v-bind en préfixe de l’attribut le rend associable à des éléments de notre DOM virtuel tels que les props, les données et les méthodes.
Voici des exemples d’usage de la directive v-bind :
jsx
<template>
<div v-bind:id="'list-' + id">
<a v-bind:href="url">Link</a>
<button v-bind:disabled="isButtonDisabled">Button</button>
</div>
</template>TIP
👌 Il est possible de raccourcir la syntaxe du prefixe v-bind: en utilisant simplement : . Exemple : :src, :href, etc.
Cas des classes et des attributs de style
Il est possible d’utiliser la directive v-bind sur les attributs class et styles pour les lier au DOM virtuel. Dans ces deux cas, où il est possible de fournir un ensemble de valeurs à l’attribut, la syntaxe s’éloigne un peu de celle en HTML. Vous devez présenter les classes et les propriétés de style sous la forme d’un objet.
Dans le cas des classes, chaque champ correspondra à un nom de classe et la valeur à une condition déterminant si la classe doit être conservée ou non :
jsx
<button v-bind:class="{valid: isValid, invalid: !isValid}">Button</button>Ici, si la variable isValid équivaut à true, la classe valid sera appliquée au bouton, sinon ce sera la classe invalid .
Dans le cas du style, chaque champ correspondra à une propriété de style CSS, et les valeurs seront celles à associer à chaque propriété. Les valeurs pourront inclure des variables de notre composant :
jsx
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>Ici, la variable activeColor pourra par exemple valoir “red” ou “green”, la variable fontSize valoir 30 ou 40 .
Autres directives
Nous avons vu ici les directives les plus communément utilisées en Vue.js. Il existe également la directive v-on nous permettant de gérer des évènements et la directive v-model intervenant dans la création d’éléments de formulaire que nous verrons plus en détail dans la prochaine partie sur l’interaction avec les composants.
Il existe aussi un certain nombre de directives plus avancées permettant d’optimiser la compilation de nos composants : v-pre, v-cloak, v-once. La directive v-slot permet également de gérer des structures de template plus complexes. Nous ne traiterons pas ces directives dans ce cours. Vous trouverez plus d’infos dessus dans la documentation Vue.js
Conclusion
Les directives nous offrent maintenant le moyen de rendre nos composants plus modulaires en fonction des données qu’ils reçoivent.
Dans le cas de notre composant DogsGallery, nous pouvons maintenant faire appel à la directive v-for pour gérer dynamiquement la création de notre composant DogCard :
jsx
<template>
<div class="dogs-gallery">
<DogCard
v-for="dog in dogsData"
:key="dog.id"
:firstname="dog.name"
:breed="dog.breed"
:pictureUrl="dog.picture"/>
</div>
</template>Peut importe que notre donnée dogsData soit un tableau vide, de 2 ou de 100 éléments, notre composant s’adaptera pour afficher correctement tous nos chiens.
Nous avons maintenant une application traitant de bout en bout l’affichage des données de notre API sur notre site. Cela nous a permis d’aborder l’essentiel des concepts de base du framework Vue.js.
Nous allons maintenant compléter ces fondamentaux en voyant comment il est possible pour nos utilisateurs d’interagir avec nos composants afin de manipuler les données présentes dans notre application.
Aller plus loin
- Sur les directives :
- Sur le v-bind de classe :

