1. v-if / v-else-if / v-else — Rendu conditionnel
v-if ajoute ou supprime réellement l'élément du DOM selon la condition.
Si la condition est fausse, l'élément n'existe tout simplement pas dans le DOM.
<div id="app">
<!-- v-if simple -->
<p v-if="estConnecte">Bienvenue, {{ prenom }} !</p>
<p v-else>Veuillez vous connecter.</p>
<!-- Chaîne v-if / v-else-if / v-else -->
<div v-if="note >= 16">🏆 Très bien</div>
<div v-else-if="note >= 12">✅ Bien</div>
<div v-else-if="note >= 10">⚠️ Passable</div>
<div v-else>❌ Insuffisant</div>
<!-- v-if sur un groupe avec <template> (sans div wrapper) -->
<template v-if="chargement">
<p>Chargement...</p>
<div class="spinner"></div>
</template>
<div v-else>Contenu chargé</div>
</div>
<script>
createApp({
data() {
return {
estConnecte: true,
prenom: 'Alice',
note: 14,
chargement: false
};
}
}).mount('#app');
</script>
<template v-if> pour conditionner un groupe d'éléments sans ajouter un <div> inutile dans le DOM.v-else et v-else-if doivent immédiatement suivre un élément v-if ou v-else-if — pas d'éléments intermédiaires.v-if + v-for : priorité
En Vue 3, v-if a une priorité plus haute que v-for (contrairement à Vue 2).
Ne les mets jamais sur le même élément. Préfère un <template v-for> avec un v-if à l'intérieur.
<!-- ❌ Mauvaise pratique : v-if + v-for sur le même élément -->
<li v-for="item in items" v-if="item.actif">{{ item.nom }}</li>
<!-- ✅ Bonne pratique -->
<template v-for="item in items" :key="item.id">
<li v-if="item.actif">{{ item.nom }}</li>
</template>
2. v-show — Visibilité CSS
v-show cache l'élément via display: none mais le laisse dans le DOM.
L'élément est toujours rendu, juste invisible.
<!-- v-show ajoute/enlève display:none -->
<div v-show="panneauOuvert">
Contenu du panneau (toujours dans le DOM)
</div>
<button @click="panneauOuvert = !panneauOuvert">Toggle</button>
<!-- Équivalent CSS de ce que fait Vue : -->
<!-- <div style="display: none;">...</div> -->
v-if vs v-show — Choisir le bon
| Critère | v-if | v-show |
|---|---|---|
| DOM | Ajouté / supprimé | Toujours présent |
| Premier rendu | Rapide si false | Toujours rendu |
| Toggle fréquent | Coûteux | Économique |
| Utilisation idéale | Conditions stables (auth, rôles) | Menus, accordéons, tooltips |
<!-- Menu dropdown : toggle fréquent → v-show -->
<ul v-show="menuOuvert" class="dropdown">...</ul>
<!-- Zone admin : condition stable → v-if -->
<section v-if="utilisateur.estAdmin">
<h2>Panneau Admin</h2>
</section>
v-if. Si les performances deviennent un problème avec de nombreux toggles, passe à v-show.3. v-for — Rendu de listes
v-for répète un élément pour chaque item d'un tableau ou d'un objet.
L'attribut :key est obligatoire et doit être unique.
<!-- Itérer un tableau simple -->
<ul>
<li v-for="fruit in fruits" :key="fruit">{{ fruit }}</li>
</ul>
<!-- Avec l'index -->
<ul>
<li v-for="(fruit, index) in fruits" :key="index">
{{ index + 1 }}. {{ fruit }}
</li>
</ul>
<!-- Tableau d'objets (clé = id unique) -->
<div v-for="tache in taches" :key="tache.id" class="tache-card">
<h3>{{ tache.titre }}</h3>
<span>{{ tache.statut }}</span>
</div>
<!-- Itérer un objet -->
<dl>
<template v-for="(valeur, cle) in config" :key="cle">
<dt>{{ cle }}</dt>
<dd>{{ valeur }}</dd>
</template>
</dl>
<!-- Générer une plage de nombres -->
<span v-for="n in 5" :key="n">{{ n }} </span>
<!-- Affiche : 1 2 3 4 5 -->
Pourquoi :key est crucial
Sans :key, Vue réutilise les éléments DOM dans l'ordre, ce qui cause des bugs visuels lors des tris, filtres ou suppressions.
Avec un :key unique (id de base de données, valeur unique), Vue sait exactement quel élément correspond à quel item.
<!-- ❌ Pas de key → bugs potentiels -->
<li v-for="item in items">{{ item.nom }}</li>
<!-- ❌ Index comme key → problèmes si la liste est triée/filtrée -->
<li v-for="(item, i) in items" :key="i">{{ item.nom }}</li>
<!-- ✅ ID unique → parfait -->
<li v-for="item in items" :key="item.id">{{ item.nom }}</li>
Méthodes de mutation réactives
Vue détecte les mutations de tableau via ces méthodes :
// ✅ Ces méthodes déclenchent la réactivité Vue :
this.items.push(nouveauItem);
this.items.pop();
this.items.shift();
this.items.unshift(item);
this.items.splice(index, 1);
this.items.sort();
this.items.reverse();
// ✅ Remplacer le tableau (aussi réactif) :
this.items = this.items.filter(i => i.actif);
this.items = [...this.items, nouveauItem]; // spread
// ❌ Mutation directe par index (non réactive en Options API) :
// this.items[0] = { nom: 'nouveau' }; // Ne pas faire !
this.items.splice(index, 1, nouvelItem) — ou utiliser la Composition API avec reactive().4. v-bind — Classe et style dynamiques
v-bind (raccourci :) lie des attributs HTML à des expressions JavaScript.
Son utilisation avec :class et :style est particulièrement puissante.
:class — Classe dynamique
<!-- Objet : { nom-classe: condition } -->
<div :class="{ actif: estActif, erreur: aDesErreurs, 'texte-grand': grandMode }"></div>
<!-- Tableau : plusieurs classes -->
<div :class="[classeBase, classeConditionnelle, { 'en-ligne': modeEnLigne }]"></div>
<!-- Expression directe (ternaire) -->
<button :class="estValide ? 'btn-succes' : 'btn-erreur'">OK</button>
<!-- Combiner class statique et :class dynamique -->
<div class="carte" :class="{ 'carte-active': estSelectionne, 'carte-large': grandFormat }"></div>
:style — Style dynamique
<!-- Objet CSS (camelCase) -->
<div :style="{ color: couleurTexte, fontSize: taille + 'px', backgroundColor: fond }"></div>
<!-- Tableau d'objets (plusieurs sources de styles) -->
<div :style="[styleBase, styleDynamique]"></div>
<!-- Variables CSS -->
<div :style="{ '--couleur-principale': couleurPrincipale }"></div>
<!-- Exemple concret : indicateur de progression -->
<div class="barre-fond">
<div
class="barre-progression"
:style="{ width: progression + '%', backgroundColor: couleur }"
></div>
</div>
Exemple complet
<div id="app">
<div
class="carte"
:class="{ 'carte-selectionnee': selectionne, 'carte-danger': score < 5 }"
:style="{ borderColor: couleur, transform: selectionne ? 'scale(1.03)' : 'none' }"
@click="selectionne = !selectionne"
>
<h3 :style="{ color: couleur }">{{ titre }}</h3>
<p>Score : {{ score }}</p>
</div>
</div>
<script>
createApp({
data() {
return {
titre: 'Ma carte',
score: 7,
couleur: '#42b883',
selectionne: false
};
}
}).mount('#app');
</script>
font-size) doivent être écrites en camelCase (fontSize) dans les objets JS, ou entre guillemets ('font-size').5. v-on (@) — Événements et modificateurs
v-on écoute les événements DOM. Son raccourci @ s'applique à n'importe quel événement natif ou personnalisé.
Les modificateurs ajoutent un comportement supplémentaire sans polluer le code de la méthode.
Modificateurs d'événement
<!-- .prevent — evt.preventDefault() -->
<form @submit.prevent="soumettreFormulaire">...</form>
<a @click.prevent="naviguer">Lien</a>
<!-- .stop — evt.stopPropagation() -->
<button @click.stop="clicBouton">Ne propage pas</button>
<!-- .self — déclenche seulement sur l'élément lui-même -->
<div @click.self="fermerModal" class="overlay">
<div class="modal">...</div>
</div>
<!-- .once — ne se déclenche qu'une seule fois -->
<button @click.once="accepterCGU">Accepter une fois</button>
<!-- .passive — améliore les performances pour scroll/touch -->
<div @scroll.passive="onScroll">...</div>
<!-- Chaîner les modificateurs -->
<form @submit.prevent.stop="soumettreFormulaire">...</form>
Modificateurs de touche clavier
<!-- Touches spécifiques -->
<input @keyup.enter="valider" placeholder="Appuie sur Entrée">
<input @keyup.esc="annuler">
<input @keyup.tab="passageSuivant">
<input @keydown.delete="supprimerDernier">
<!-- Touches de modification -->
<button @click.ctrl="sauvegarder">Ctrl+Clic pour sauvegarder</button>
<button @click.shift="selectionner">Shift+Clic</button>
<!-- Touches exactes -->
<input @keyup.ctrl.z.exact="annulerAction">
<input @keyup.alt.enter.exact="envoyerEtNouvelle">
Modificateurs de souris
<button @click.left="clicGauche">Clic gauche</button>
<button @click.right.prevent="menuContextuel">Clic droit</button>
<button @click.middle="ouvrirOnglet">Clic milieu</button>
@submit.prevent = "quand submit, empêche le comportement par défaut".6. v-model — Liaisons et modificateurs
v-model crée une liaison bidirectionnelle entre un champ de formulaire et une donnée Vue.
Il s'adapte automatiquement au type de l'élément.
Types de champs
<div id="app">
<!-- Input texte -->
<input v-model="texte" type="text">
<!-- Input nombre -->
<input v-model.number="age" type="number">
<!-- Checkbox -->
<input v-model="accepte" type="checkbox"> J'accepte
<!-- Checkbox multiple (tableau) -->
<input v-model="couleurs" value="rouge" type="checkbox"> Rouge
<input v-model="couleurs" value="bleu" type="checkbox"> Bleu
<!-- Radio -->
<input v-model="genre" value="homme" type="radio"> Homme
<input v-model="genre" value="femme" type="radio"> Femme
<!-- Select -->
<select v-model="pays">
<option value="">Choisir...</option>
<option value="fr">France</option>
<option value="be">Belgique</option>
</select>
<!-- Select multiple -->
<select v-model="langues" multiple>
<option v-for="l in languesDisponibles" :key="l" :value="l">{{ l }}</option>
</select>
<!-- Textarea -->
<textarea v-model="message"></textarea>
</div>
Modificateurs v-model
<!-- .lazy — mise à jour au changement (blur), pas à chaque frappe -->
<input v-model.lazy="texte">
<!-- .number — convertit la valeur en nombre automatiquement -->
<input v-model.number="quantite" type="number">
<!-- Sans .number : "42" (string) → Avec .number : 42 (number) -->
<!-- .trim — enlève les espaces en début et fin -->
<input v-model.trim="email">
<!-- Combiner les modificateurs -->
<input v-model.trim.lazy="nom">
Exemple formulaire complet
<form @submit.prevent="soumettreFormulaire">
<input v-model.trim="form.nom" placeholder="Nom">
<input v-model.trim="form.email" type="email" placeholder="Email">
<input v-model.number="form.age" type="number" placeholder="Âge">
<textarea v-model.trim="form.message" placeholder="Message"></textarea>
<select v-model="form.pays">
<option v-for="p in pays" :key="p.code" :value="p.code">{{ p.nom }}</option>
</select>
<input v-model="form.cgu" type="checkbox"> J'accepte les CGU
<button type="submit" :disabled="!form.cgu">Envoyer</button>
</form>
<!-- Aperçu en temps réel -->
<pre>{{ JSON.stringify(form, null, 2) }}</pre>
.number et .trim sont les modificateurs les plus utiles en pratique — ils évitent les surprises de typage dans tes données.