Frameworks

Introduction à Vue.js 3 : Le Guide Complet

Mark Toledo

Mark Toledo

5 janvier 2025

Introduction à Vue.js 3 : Le Guide Complet

Vue.js 3 représente une évolution majeure du framework JavaScript progressif. Avec la Composition API, un système de réactivité repensé et des performances améliorées, Vue 3 s'impose comme un choix excellent pour le développement frontend moderne.

Pourquoi Vue.js ?

Vue.js se distingue par sa progressivité : vous pouvez l'adopter graduellement, d'une simple page à une application complexe. Son approche équilibrée entre simplicité et puissance en fait un choix populaire.

Points forts

  • Courbe d'apprentissage douce
  • Documentation excellente (en français !)
  • Écosystème complet : Vue Router, Pinia, Nuxt
  • Performances optimales avec le Virtual DOM amélioré
  • TypeScript natif

Installation

Via CDN (prototypage)

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

Via Vite (recommandé)

npm create vite@latest mon-app -- --template vue
cd mon-app
npm install
npm run dev

La Composition API

Vue 3 introduit la Composition API, une nouvelle façon d'organiser la logique des composants.

Composant basique

<template>
  <div>
    <h1>{{ titre }}</h1>
    <p>Compteur : {{ compteur }}</p>
    <button @click="incrementer">+1</button>
  </div>
</template>

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

// État réactif
const titre = ref('Mon Application Vue')
const compteur = ref(0)

// Méthode
function incrementer() {
  compteur.value++
}
</script>

<style scoped>
h1 {
  color: #42b883;
}
</style>

ref vs reactive

import { ref, reactive } from 'vue'

// ref - pour valeurs primitives
const compteur = ref(0)
compteur.value++ // Accès via .value

// reactive - pour objets
const utilisateur = reactive({
  nom: 'Mark',
  age: 39
})
utilisateur.nom = 'Mark Toledo' // Accès direct

Computed (propriétés calculées)

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

const prenom = ref('Mark')
const nom = ref('Toledo')

// Propriété calculée (automatiquement mise à jour)
const nomComplet = computed(() => {
  return `${prenom.value} ${nom.value}`
})
</script>

Watch (surveillance)

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

const recherche = ref('')

// Surveiller une ref spécifique
watch(recherche, (nouvelleValeur, ancienneValeur) => {
  console.log(`Recherche changée de "${ancienneValeur}" à "${nouvelleValeur}"`)
})

// watchEffect - exécuté immédiatement et sur changement
watchEffect(() => {
  console.log('Recherche actuelle:', recherche.value)
})
</script>

Les composants

Création d'un composant

<!-- components/BoutonAction.vue -->
<template>
  <button
    :class="['btn', `btn-${variante}`]"
    @click="$emit('clic')"
  >
    <slot>Action</slot>
  </button>
</template>

<script setup>
defineProps({
  variante: {
    type: String,
    default: 'primary',
    validator: (v) => ['primary', 'secondary', 'danger'].includes(v)
  }
})

defineEmits(['clic'])
</script>

<style scoped>
.btn {
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.btn-primary { background: #42b883; color: white; }
.btn-secondary { background: #35495e; color: white; }
.btn-danger { background: #e74c3c; color: white; }
</style>

Utilisation

<template>
  <BoutonAction variante="primary" @clic="sauvegarder">
    Sauvegarder
  </BoutonAction>
</template>

<script setup>
import BoutonAction from './components/BoutonAction.vue'

function sauvegarder() {
  console.log('Sauvegarde en cours...')
}
</script>

Directives essentielles

v-if / v-else / v-show

<template>
  <!-- Rendu conditionnel (ajoute/supprime du DOM) -->
  <div v-if="estConnecte">Bienvenue !</div>
  <div v-else>Veuillez vous connecter</div>

  <!-- Affichage conditionnel (toggle CSS display) -->
  <div v-show="menuOuvert">Menu déroulant</div>
</template>

v-for (boucles)

<template>
  <ul>
    <li v-for="(item, index) in items" :key="item.id">
      {{ index + 1 }}. {{ item.nom }}
    </li>
  </ul>
</template>

v-model (liaison bidirectionnelle)

<template>
  <input v-model="email" type="email" />
  <p>Email saisi : {{ email }}</p>

  <!-- Modificateurs -->
  <input v-model.trim="nom" />
  <input v-model.number="age" type="number" />
  <input v-model.lazy="commentaire" />
</template>

Cycle de vie

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

// Après le montage du composant
onMounted(() => {
  console.log('Composant monté')
  // Idéal pour : appels API, abonnements, accès DOM
})

// Après chaque mise à jour
onUpdated(() => {
  console.log('Composant mis à jour')
})

// Avant la destruction
onUnmounted(() => {
  console.log('Composant détruit')
  // Nettoyage : désabonnements, timers, etc.
})
</script>

Composables (réutilisation de logique)

// composables/useCompteur.js
import { ref } from 'vue'

export function useCompteur(initial = 0) {
  const compteur = ref(initial)

  function incrementer() {
    compteur.value++
  }

  function decrementer() {
    compteur.value--
  }

  function reinitialiser() {
    compteur.value = initial
  }

  return {
    compteur,
    incrementer,
    decrementer,
    reinitialiser
  }
}

// Utilisation dans un composant
<script setup>
import { useCompteur } from '@/composables/useCompteur'

const { compteur, incrementer, decrementer } = useCompteur(10)
</script>

Gestion d'état avec Pinia

npm install pinia
// stores/user.js
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    utilisateur: null,
    estConnecte: false
  }),

  getters: {
    nomComplet: (state) => {
      return state.utilisateur
        ? `${state.utilisateur.prenom} ${state.utilisateur.nom}`
        : 'Invité'
    }
  },

  actions: {
    async connecter(credentials) {
      const response = await fetch('/api/login', {
        method: 'POST',
        body: JSON.stringify(credentials)
      })
      this.utilisateur = await response.json()
      this.estConnecte = true
    },

    deconnecter() {
      this.utilisateur = null
      this.estConnecte = false
    }
  }
})

// Utilisation
<script setup>
import { useUserStore } from '@/stores/user'

const userStore = useUserStore()
</script>

<template>
  <p>{{ userStore.nomComplet }}</p>
  <button @click="userStore.deconnecter()">Déconnexion</button>
</template>

Conclusion

Vue.js 3 offre une expérience de développement agréable avec la Composition API et un écosystème mature. Sa progressivité permet de l'adopter à votre rythme, du simple widget à l'application complexe.

Dans les prochains articles, nous explorerons Nuxt 3 pour le rendu côté serveur et le développement fullstack avec Vue.js.