Skip to content

Les composants Vue.js

Cette section décrit comment créer des composants réutilisables en Vue 3 avec la Composition API, et comment transmettre des données et des événements entre les composants à l'aide des props, des emits et des * slots*.

1. Composants

📘 Documentation

🎯 Objectif

Créer des éléments réutilisables pour structurer une application en petites unités.

💡 Utilité

Les composants permettent de diviser l’interface utilisateur en blocs indépendants, faciles à gérer, à réutiliser et à tester.

composants.png

💻 Exemple

vue
<!-- src/components/BoutonCompteur.vue -->
<template>
  <v-btn @click="incrementer">Compteur : {{ compteur }}</v-btn>
</template>

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

  const compteur = ref(0)
  const incrementer = () => compteur.value++
</script>
vue
<!-- src/pages/Home.vue -->
<template>
  <BoutonCompteur/>
</template>

✅ Bonnes pratiques

  • Toujours donner un nom clair et PascalCase au fichier et au composant
  • Garder un composant court et ciblé sur une seule fonctionnalité
  • Sauvegarder les composants dans le dossier src/components/ et les pages dans src/pages/.
  • Regrouper les composants par fonctionnalité ou domaine d’application dans des sous-dossiers (ex. : src/components/compteur/ ou src/components/formulaire/)

2. Props (propriétés)

📘 Documentation

🎯 Objectif

Permettre à un composant parent de transmettre des données à un composant enfant.

On déclare les props dans le composant enfant avec defineProps().

💡 Utilité

Les props permettent de rendre les composants dynamiques et personnalisables.

💻 Exemple

vue
<!-- Composant enfant : Salut.vue -->
<template>
  <p>Bonjour {{ prenom }} !</p>
  <p>Tu as {{ age }} ans.</p>
</template>

<script setup>
  import {defineProps} from 'vue'
  
  // Déclaration des props
  defineProps({
    prenom: {         // nom de la prop
      type: String,   // type de la prop
      required: true  // obligatoire
    },
    age: {            // nom de la prop
      type: Number,   // type de la prop
      default: 10     // valeur par défaut
    }
  })
</script>
vue
<!-- Utilisation dans un parent -->
<template>
    <Salut prenom="Sacha" :age="17" />
    <button @click="age++">Anniversaire</button>
</template>

<script setup>
  import {ref} from 'vue'
  // Importation du composant enfant
  import Salut from '../components/Salut.vue'

  const age = ref(17)
</script>

✅ Bonnes pratiques

  • Toujours définir les props explicitement avec defineProps()
  • Valider le type (String, Number, etc.)
  • Utiliser required: true pour les props obligatoires
  • Utiliser default pour les props optionnelles
  • Si une prop est dynamique, utiliser v-bind ou : pour la lier à une variable (ex. : :age="age" ou v-bind:age="age")

3. Emits (événements personnalisés)

📘 Documentation

🎯 Objectif

Permettre à un composant enfant de notifier son parent d’un événement et de lui transmettre des données.

Les événements sont déclarés dans le composant enfant avec defineEmits().

💡 Utilité

Seul moyen pour un enfant de communiquer avec son parent et de transmettre des données.

Par exemple, un bouton enfant peut émettre un événement ajoute lorsqu’il est cliqué, et le parent peut écouter cet événement pour réagir en conséquence (ex. : ajouter un élément à une liste).

💻 Exemple

vue
<!-- Composant enfant -->
<template>
  <button @click="$emit('ajouteAssaisonnement', 'sel')">
    Ajouter du sel
  </button>
  <button @click="$emit('ajouteAssaisonnement', 'poivre')">
    Ajouter du poivre
  </button>
</template>

<script setup>
  const emit = defineEmits(['ajouteAssaisonnement'])
</script>
vue
<!-- Composant parent -->
<template>
  <BoutonAjout @ajoute-assaisonnement="assaisonner"/>
</template>

<script setup>
  const assaisonner = (element) => console.log('Vous avez ajouté du :', element)
</script>

✅ Bonnes pratiques

  • Toujours déclarer les événements avec defineEmits()
  • Nommer les événements en kebab-case dans le template parent (@mon-evenement)

4. Slots (contenu personnalisé)

📘 Documentation

🎯 Objectif

Permettre au parent d’injecter du contenu dans un composant enfant entre les balises d’ouverture et de fermeture.

💡 Utilité

Utile pour créer des composants « conteneurs » comme des cartes, modales ou boutons personnalisés pour y insérer du contenu html dynamique.

💻 Exemple

vue
<!-- Composant Boite.vue -->
<template>
  <div class="box">
    <slot/> <!-- Zone de contenu personnalisée -->
  </div>
</template>
vue
<!-- Utilisation -->
<Boite>
  <p>Contenu personnalisé à l’intérieur !</p> <!-- Injecté dans le slot -->
</Boite>

✅ Bonnes pratiques

  • Utiliser slot sans nom pour un contenu simple
  • Utiliser name pour gérer plusieurs emplacements (<slot name="header" />)
  • Documenter les slots attendus dans vos composants

Slots nommés

On peut aussi créer des slots nommés pour injecter du contenu à des endroits spécifiques dans le composant enfant.

vue
<!-- Composant Boite.vue -->
<template>
  <div class="box">
    <header>
      <slot name="header"/> <!-- Slot nommé -->
    </header>
    <main>
      <slot/> <!-- Slot par défaut -->
    </main>
    <footer>
      <slot name="footer"/> <!-- Slot nommé -->
    </footer>
  </div>
</template>
vue
<!-- Utilisation -->
<Boite>
  <template #header>
    <h1>Titre de la boîte</h1> <!-- Injecté dans le slot nommé "header" -->
  </template>
  <p>Contenu principal de la boîte !</p> <!-- Injecté dans le slot par défaut -->
  <template #footer>
    <p>Pied de page de la boîte</p> <!-- Injecté dans le slot nommé "footer" -->
  </template>
</Boite>