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.
💻 Exemple
<!-- 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>
<!-- 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 danssrc/pages/
. - Regrouper les composants par fonctionnalité ou domaine d’application dans des sous-dossiers (ex. :
src/components/compteur/
ousrc/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
<!-- 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>
<!-- 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"
ouv-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
<!-- 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>
<!-- 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
<!-- Composant Boite.vue -->
<template>
<div class="box">
<slot/> <!-- Zone de contenu personnalisée -->
</div>
</template>
<!-- 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.
<!-- 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>
<!-- 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>