Composants monofichiers et syntaxe des templates

Première leçon du cours Vue.js, en accès libre : environ 17 minutes, 4 exercices et 3 questions de quiz. C'est la leçon de base du catalogue ; dans l'espace étudiant, elle est réécrite pour ton profil.

Objectifs

  • Créer un projet Vue et écrire un composant monofichier avec <script setup>
  • Utiliser l'interpolation et les directives v-bind, v-on, v-if, v-show et v-for
  • Extraire la logique d'affichage dans des fonctions pures testables

Composants monofichiers (SFC)Syntaxe des templatesDirectives v-if, v-for, v-bind, v-on

Créer un projet Vue

Vue est un framework JavaScript progressif pour construire des interfaces : on peut l’ajouter à une page existante ou bâtir une application complète. Le point de départ recommandé est l’outil officiel create-vue, basé sur Vite :

npm create vue@latest     # questions : TypeScript, puis Router, Pinia, Vitest…
cd mon-projet
npm install
npm run dev               # serveur de développement Vite avec rechargement à chaud

Le projet utilise Vue 3.5 et Vite 8 (Node.js 22.18 ou plus récent ; la LTS actuelle, Node 26, convient). La première question, « Use TypeScript? », est cochée Yes par défaut : ce cours étant écrit en JavaScript, répondez No. On peut aussi tout indiquer en ligne de commande : npm create vue@latest mon-projet -- --router --pinia --vitest crée directement un projet JavaScript avec ces options (ajoutez --ts pour TypeScript).

Le projet contient src/main.js, qui crée l’application (createApp(App).mount('#app')), et des fichiers .vue : les composants monofichiers (Single-File Components).

Anatomie d’un composant

<script setup>
import { ref } from 'vue'

const titre = 'Mes tâches'
const taches = ref([
  { id: 1, libelle: 'Acheter du pain', faite: false },
  { id: 2, libelle: 'Réviser Vue', faite: true },
])
function basculer(tache) {
  tache.faite = !tache.faite
}
</script>

<template>
  <h1>{{ titre }}</h1>
  <ul>
    <li v-for="tache in taches" :key="tache.id" :class="{ faite: tache.faite }">
      <label>
        <input type="checkbox" :checked="tache.faite" @change="basculer(tache)" />
        {{ tache.libelle }}
      </label>
    </li>
  </ul>
  <p v-if="taches.length === 0">Aucune tâche.</p>
</template>

<style scoped>
.faite { text-decoration: line-through; }
</style>
  • <script setup> est la syntaxe recommandée avec la Composition API : toute variable, fonction ou composant importé y est directement disponible dans le template.
  • <template> décrit le HTML, enrichi par la syntaxe de Vue.
  • <style scoped> limite les styles à ce composant.

ref() rend une valeur réactive : quand elle change, Vue met à jour l’affichage. La leçon suivante détaille la réactivité.

Interpolation et liaisons

  • {{ expression }} affiche une expression JavaScript (pas une instruction : pas de if ni de for).
  • v-bind:attribut ou son raccourci :attribut lie un attribut à une expression : :disabled="panierVide", :href="url".
  • v-on:evenement ou @evenement écoute un événement : @click="ajouter", @submit.prevent="envoyer" (le modificateur .prevent appelle preventDefault()).
  • v-model crée une liaison bidirectionnelle avec un champ : <input v-model="recherche" />.

Rendu conditionnel et listes

v-if / v-else-if / v-else créent ou détruisent l’élément ; v-show le garde dans le DOM et le masque avec display: none. On préfère v-show pour un élément basculé très souvent, v-if pour un contenu rarement affiché ou coûteux.

v-for répète un élément pour chaque entrée d’une liste. Il exige une :key unique et stable, typiquement l’identifiant de l’élément. Avec l’index comme clé, Vue réutilise les mauvais éléments quand on trie ou supprime, et l’état interne (un champ en cours de saisie) se retrouve sur la mauvaise ligne. Évitez aussi v-if et v-for sur le même élément : filtrez plutôt la liste en amont.

Classes et styles dynamiques

:class accepte un objet (la classe est appliquée si la valeur est vraie) ou un tableau :

<button :class="['btn', `btn--${variante}`, { 'btn--desactive': desactive }]">

Extraire la logique d’affichage

Un template doit rester lisible. Dès qu’une expression devient complexe (filtrer selon un critère, construire des classes, formater un libellé), placez-la dans une fonction pure : elle reçoit des données et renvoie un résultat, sans effet de bord. Elle se teste sans navigateur et se réutilise :

// src/logique/taches.js
export function filtrerTaches(taches, filtre) {
  if (filtre === 'actives') return taches.filter((t) => !t.faite)
  if (filtre === 'faites') return taches.filter((t) => t.faite)
  return taches
}

Le composant l’utilise ensuite dans le template ou, mieux, dans une propriété calculée (computed), vue à la leçon suivante. C’est ce que vous pratiquerez dans les exercices de code de ce cours : la logique en JavaScript pur, les composants dans des tâches pratiques.

À retenir

Composant = script + template + style. : pour lier, @ pour écouter, v-if/v-show pour afficher, v-for avec une :key stable pour répéter, et une logique d’affichage extraite en fonctions pures.

Exercices

Les solutions et les tests restent sur le serveur. Dans l'espace étudiant, ton code est exécuté et corrigé, et le tuteur donne des indices avant la solution.

  1. CodeDifficulté 1JavaScript dans le navigateur2 indices

    Filtrer une liste de tâches

    Logique utilisée par le composant de liste. Écrivez :

    • filtrerTaches(taches, filtre) qui renvoie toutes les tâches pour "toutes", les tâches non faites pour "actives", les tâches faites pour "faites". Un filtre inconnu lève une erreur Filtre inconnu.
    • libelleRestantes(taches) qui renvoie "Aucune tâche restante", "1 tâche restante" ou "N tâches restantes".

    Ne modifiez jamais le tableau reçu.

    function filtrerTaches(taches, filtre) {
      // TODO
    }
    
    function libelleRestantes(taches) {
      // TODO
    }
  2. CodeDifficulté 2JavaScript dans le navigateur2 indices

    Classes d'un bouton

    Le composant BoutonApp calcule sa liste de classes pour :class. Écrivez classesBouton(options) qui reçoit un objet { variante, taille, desactive } (toutes les propriétés facultatives) et renvoie un tableau :

    • toujours "btn" ;
    • "btn--<variante>" avec variante valant "primaire" par défaut ; seules "primaire", "secondaire" et "danger" sont acceptées, sinon erreur Variante inconnue ;
    • "btn--<taille>" avec taille valant "m" par défaut ;
    • "btn--desactive" en dernier, seulement si desactive est vrai.
    function classesBouton(options = {}) {
      // TODO
    }
  3. TâcheDifficulté 22 indices

    Premier composant : la liste de tâches

    Créez un projet avec npm create vue@latest (répondez No à TypeScript et ne cochez aucune fonctionnalité), puis remplacez le contenu de App.vue par un composant de liste de tâches :

    1. Données initiales (dans un ref) :
    id,libelle,faite
    1,Acheter du pain,false
    2,Réviser Vue,true
    3,Appeler le garage,false
    1. Affichez chaque tâche avec une case à cocher liée à faite, avec v-for et :key="tache.id".
    2. Ajoutez trois boutons de filtre (Toutes, Actives, Faites) qui utilisent votre fonction filtrerTaches.
    3. Affichez sous la liste le texte produit par libelleRestantes.
    • v-for utilise :key avec l'identifiant de la tâche
    • Les boutons de filtre changent la liste affichée sans modifier les données
    • Cocher une tâche met à jour le compteur immédiatement
    • Les fonctions de filtre et de libellé sont importées d'un fichier .js séparé
  4. QCMDifficulté 11 indice

    v-if ou v-show ?

    Un panneau d’aide est ouvert et fermé très souvent par l’utilisateur. Quelle directive est la plus adaptée, et pourquoi ?

    • v-if, car il est plus rapide à chaque bascule
    • v-show, car l'élément reste dans le DOM et seule sa visibilité CSS change
    • v-for, pour répéter le panneau
    • Aucune différence entre les deux

Quiz de fin de leçon

  1. Que fait :disabled="panierVide" ?

    • Il donne à l'attribut la chaîne "panierVide"
    • Il lie l'attribut disabled à la valeur de l'expression panierVide
    • Il écoute l'événement disabled
  2. Pourquoi éviter l’index comme :key dans un v-for ?

    • Il est interdit par Vue
    • Quand la liste est triée ou modifiée, Vue associe l'état aux mauvais éléments
    • Il ralentit le premier affichage
  3. Qu’est-ce qui est disponible dans le template d’un composant

    • Seules les variables exportées
    • Les variables, fonctions et imports déclarés au niveau supérieur du script
    • Rien sans la méthode data()

La suite du cours

  1. Réactivité et Composition API19 min
  2. Props, événements, v-model et slots18 min
  3. Navigation avec Vue Router18 min
  4. État partagé avec Pinia et tests19 min

Vue.js · Intermédiaire · 1 h 31