Retour à tous les articles

Cours Vue.js

Vue.js

17 avr. 2026

Sommaire

  1. Introduction à Vue.js
  2. Créer une première application
  3. Interagir avec le DOM
  4. Données et méthodes
  5. Formulaires
  6. Les bases des composants
  7. Les composants en détails
  8. Cycle de vie des composants

1. Introduction à Vue.js

Qu'est-ce que Vue.js ?

Vue.js est un framework open-source JavaScript créé en 2014 par Evan You (ex-Google, également créateur de Vite). Il permet de créer des interfaces utilisateurs en utilisant des composants réactifs, basé sur HTML / CSS / JavaScript. Actuellement en version 3.5+.

Un framework évolutif

  • Adoption progressive : peut gérer une simple partie d'une page existante, sans router ni store obligatoire.
  • Montée en complexité maîtrisée : intégration optionnelle de Vue Router, Pinia et Vite.
  • Aucune architecture imposée : liberté dans l'organisation du code, du petit projet à une application fullstack avec Nuxt (SSR, SSG).

Vue vs. React vs. Angular vs. Svelte

Angular React Vue Svelte
Type Framework complet Bibliothèque UI Framework progressif Framework compilé
Apprentissage Difficile Moyen Facile Facile
Performance Bonne Bonne Très bonne Excellente
Créé par Google Meta Evan You Rich Harris
Année 2010 2013 2014 2016

Vue.js : excellent compromis entre simplicité et puissance, syntaxe proche du HTML, montée en complexité progressive.

Composant mono-fichier (SFC)

Vue utilise des Single-File Components (.vue). Le JavaScript, le HTML et le CSS sont réunis dans un seul fichier.

<script>
  // Code JavaScript ici.
</script>

<template>
  <!-- Code HTML ici. -->
</template>

<style>
  /* Code CSS ici. */
</style>

Options API vs. Composition API

Vue propose deux styles d'API :

Options API (historique, Vue 2) :

<script>
export default {
  data() { return { count: 0 } },
  methods: {
    increment() { this.count++ }
  },
  mounted() { console.log(this.count) }
}
</script>

Composition API (recommandée, Vue 3) :

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

const count = ref(0)
function increment() { count.value++ }
onMounted(() => console.log(count.value))
</script>
Critères Options API Composition API
Organisation Par sections (data, methods…) Par fonctionnalités
Réutilisabilité Difficile sans mixins Facile via fonctions/hooks
Complexité Simple pour composants basiques Meilleure pour composants complexes
Performance Vue 2 Optimisée pour Vue 3

💡 Dans ce cours, on utilisera uniquement la Composition API.


2. Créer une première application

Installation

Prérequis : avoir Node.js et npm installés.

npm create vue@latest

Lors de l'installation, sélectionner : TypeScript, ESLint, Prettier (au minimum).

cd mon-projet
npm install && npm run dev

Architecture d'un projet Vue

/public         → assets statiques
/src
  main.ts       → fichier d'entrée, initialise Vue.js
  App.vue       → composant principal
  /components   → composants réutilisables
  /pages        → pages de l'application

💡 Par convention, les fichiers de composants sont nommés en PascalCase (ex: MonComposant.vue).


3. Interagir avec le DOM

Interpolation de données

Affichage dynamique avec la syntaxe Moustache {{ }} :

<script setup>
const message = "Hello World";
</script>

<template>
  <p>{{ message }}</p>
  <p>{{ 2 + 2 }}</p>  <!-- Affiche 4 -->
</template>

Les directives

Une directive est un attribut spécial commençant par v- qui lie du JavaScript au DOM.

Directive Rôle
v-text Afficher du texte dynamique
v-html Interpréter du HTML (⚠️ risque XSS)
v-bind / : Lier des attributs HTML dynamiquement
v-model Liaison bidirectionnelle avec un champ
v-if / v-else-if / v-else Rendu conditionnel
v-show Afficher/masquer (via display: none)
v-for Boucles sur tableaux et objets
v-on / @ Écouter des événements

v-bind et son raccourci

<img v-bind:src="imageUrl" v-bind:alt="imageAlt"/>
<!-- Équivalent (recommandé) -->
<img :src="imageUrl" :alt="imageAlt"/>

v-model

<input type="text" v-model="nom" placeholder="Votre nom"/>
<p>Bonjour, {{ nom }} !</p>

v-if / v-else

<p v-if="nom">Bonjour {{ nom }} !</p>
<p v-else>Bonjour inconnu !</p>

💡 Utilisez v-show si vous alternez fréquemment, v-if si le changement est rare.

v-for

<li v-for="(person, index) in people" :key="person.name">
  {{ index }} - {{ person.name }} ({{ person.age }} ans)
</li>

Gestion des événements

<button @click="direBonjour('Alice')">Dire bonjour</button>

Modificateurs d'événements

Modificateur Description
.stop Arrête la propagation
.prevent Empêche le comportement par défaut
.once L'événement ne se déclenche qu'une fois
.self Uniquement si l'élément lui-même est la cible
<form @submit.prevent="submitForm">...</form>
<button @click.once="sayHello">Dire bonjour</button>
<input @keyup.enter="submit"/>

4. Données et méthodes

La réactivité

Vue crée un système réactif basé sur des Proxys JavaScript. Toute modification d'une variable réactive déclenche une mise à jour automatique de la vue.

reactive() — pour les objets

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

const user = reactive({ name: "Alice", age: 25 })
user.age++ // Vue détecte le changement !
</script>

⚠️ Limitations : ne fonctionne pas avec les primitives, impossible de déstructurer sans perdre la réactivité.

ref() — pour tout type de valeur

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

const name = ref('Alice')
const age = ref(25)
age.value++ // Utiliser .value dans le script
</script>

<template>
  <p>{{ name }} a {{ age }} ans</p>
  <!-- Dans le template, pas besoin de .value -->
</template>
reactive() ref()
Type Objets uniquement Primitifs & objets
Accès Direct .value obligatoire (dans le script)
Usage Structures complexes Valeurs simples

💡 On peut tout à fait n'utiliser que ref() pour ne plus avoir à choisir.

Propriétés calculées (computed)

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

const prixHT = ref(100)
const tva = 0.2
const prixTTC = computed(() => prixHT.value * (1 + tva))
</script>

Les propriétés computed sont mises en cache et ne se recalculent que si leurs dépendances changent. Préférer computed aux méthodes pour calculer des valeurs dérivées.

Observateurs (watch)

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

const compteur = ref(0)
watch(compteur, (nouveau, ancien) => {
  console.log(`Compteur changé de ${ancien} à ${nouveau}`)
})
</script>

Pour surveiller un objet en profondeur :

watch(utilisateur, (nouveau) => { ... }, { deep: true })

watchEffect s'exécute immédiatement et réagit automatiquement :

watchEffect(() => {
  console.log(`Message actuel : ${message.value}`)
})
computed watch methods
Mise en cache
Usage Valeurs dérivées Actions sur changement Exécution d'actions
Async

5. Formulaires

Champs avec v-model

<!-- Input texte -->
<input type="text" v-model="message"/>

<!-- Textarea -->
<textarea v-model="message"></textarea>

<!-- Checkbox (booléen) -->
<input type="checkbox" v-model="checked"/>

<!-- Radio -->
<input type="radio" value="Choix n°1" v-model="choice"/>
<input type="radio" value="Choix n°2" v-model="choice"/>

<!-- Select -->
<select v-model="choice">
  <option v-for="option in options" :key="option.value" :value="option.value">
    {{ option.text }}
  </option>
</select>

Modificateurs de v-model

Modificateur Effet
.lazy Synchronise sur l'événement change (pas input)
.number Convertit la valeur en nombre
.trim Supprime les espaces avant/après
<input type="email" v-model.trim="email"/>
<input type="number" v-model.number="age"/>

6. Les bases des composants

Introduction

Les composants sont les blocs de construction d'une application Vue. Chaque composant représente une partie réutilisable de l'interface (ex: <Header/>, <Button/>, <FormContact/>).

Utiliser un composant

<script setup>
import MonComposant from './MonComposant.vue'
</script>

<template>
  <MonComposant/>
</template>

Props — passer des données parent → enfant

<!-- Parent.vue -->
<Enfant message="Hello !"/>

<!-- Enfant.vue -->
<script setup>
defineProps(['message'])
</script>
<template>
  <p>{{ message }}</p>
</template>

⚠️ Il est interdit de modifier une prop directement depuis le composant enfant.

Emit — envoyer un événement enfant → parent

<!-- Enfant.vue -->
<script setup>
const emit = defineEmits(['increment'])
</script>
<template>
  <button @click="emit('increment')">+1</button>
</template>

<!-- Parent.vue -->
<Enfant @increment="compteur++"/>

Slots — insérer du contenu dans un composant

<!-- MaCard.vue -->
<template>
  <div class="card">
    <slot/>
  </div>
</template>

<!-- Parent.vue -->
<MaCard>
  <p>Contenu inséré dans le slot</p>
</MaCard>

Organisation recommandée

/src
  /components   → composants UI réutilisables
  /pages        → pages principales
  /layouts      → templates de mise en page

7. Les composants en détails

Props typées et validées

<script setup>
defineProps({
  titre: String,
  compteur: {
    type: Number,
    required: true,
    default: 0
  },
  type: {
    type: String,
    required: true,
    validator(value) {
      return ['success', 'warning', 'danger'].includes(value)
    }
  }
})
</script>

Équivalent TypeScript :

<script setup lang="ts">
const props = defineProps<{
  message: string
  type: 'success' | 'warning' | 'danger'
}>()
</script>

v-model sur un composant personnalisé

<!-- Parent.vue -->
<MonComposant v-model="texte"/>

<!-- Enfant.vue (Vue >= 3.4) -->
<script setup>
const model = defineModel()
</script>
<template>
  <input type="text" v-model="model"/>
</template>

Attributs implicites ($attrs)

Par défaut, les attributs passés à un composant sont appliqués à son élément racine. Pour désactiver ce comportement et les appliquer manuellement :

<script setup>
defineOptions({ inheritAttrs: false })
</script>
<template>
  <label>Mon input</label>
  <input type="text" v-bind="$attrs"/>
</template>

Provide / Inject

Partager des données entre un composant ancêtre et ses descendants sans passer par les props à chaque niveau.

<!-- Fournisseur (parent ou layout) -->
<script setup>
import { provide, ref } from 'vue'
const theme = ref('dark')
provide('theme', theme)
</script>

<!-- Consommateur (n'importe quel descendant) -->
<script setup>
import { inject } from 'vue'
const theme = inject('theme')
</script>

Composants asynchrones

<script setup>
import { defineAsyncComponent } from 'vue'
const AsyncComponent = defineAsyncComponent(() => import('./MonComposant.vue'))
</script>

8. Cycle de vie des composants

Les phases

Un composant Vue passe par 4 phases :

1. Création

  • beforeCreate : composant initialisé, données pas encore disponibles.
  • created : données réactives, props, computed disponibles. DOM inexistant.

2. Montage

  • beforeMount : template compilé, DOM pas encore inséré.
  • mounted : composant inséré dans le DOM. ✅ Accès au DOM possible.

3. Mise à jour

  • beforeUpdate : une donnée change, DOM pas encore mis à jour.
  • updated : DOM mis à jour.

4. Destruction

  • beforeUnmount : composant sur le point d'être retiré. Idéal pour nettoyer (timers, listeners).
  • unmounted : composant totalement détruit.

Utilisation des hooks

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'

const count = ref(0)
let interval

onMounted(() => {
  interval = setInterval(() => { count.value++ }, 1000)
})

onBeforeUnmount(() => {
  clearInterval(interval) // Nettoyage !
})
</script>

Écouter le redimensionnement de la fenêtre

<script setup>
import { onMounted, onBeforeUnmount } from 'vue'

function handleResize() {
  console.log('Largeur :', window.innerWidth)
}

onMounted(() => window.addEventListener('resize', handleResize))
onBeforeUnmount(() => window.removeEventListener('resize', handleResize))
</script>