Cours Vue.js · Module 6: Composants
La composition de composants
Dans cette leçon6
Le Dr Nova poursuit : « La station NOVA LAB n'est pas un bloc monolithique - c'est un arbre de modules : la station principale contient des sections, les sections contiennent des salles, et les salles contiennent des équipements. Nous construisons les applications Vue de la même façon - à partir d'une hiérarchie de composants. »
Imagine un panneau de commande écrit dans un seul fichier de mille lignes. L'en-tête, la liste des modules, les boutons de commande et le pied de page s'y mélangent, et un bug dans un bouton doit être traqué dans tout le fichier. Un tel monolithe est difficile à lire, à tester et à faire évoluer.
Qu'est-ce que la composition de composants ?
La composition est un modèle qui consiste à construire des interfaces complexes à partir de composants plus simples et plus petits. Au lieu d'un énorme composant de mille lignes de code, on découpe l'interface en parties logiques, et le composant racine se contente de les disposer :
1<!-- App.vue - racine de l'arbre de composants -->
2<template>
3 <div class="station">
4 <StationHeader />
5 <main>
6 <ModuleList />
7 <ControlPanel />
8 </main>
9 <StationFooter />
10 </div>
11</template>
12
13<script setup>
14import StationHeader from './components/StationHeader.vue'
15import ModuleList from './components/ModuleList.vue'
16import ControlPanel from './components/ControlPanel.vue'
17import StationFooter from './components/StationFooter.vue'
18</script>Le template de App.vue se lit maintenant comme la liste des sections de la station. La façon d'utiliser les composants n'a pas changé - ce sont les mêmes imports et les mêmes balises que dans la leçon précédente, simplement plus nombreux.
La relation parent-enfant
Quand un composant utilise un autre composant dans son template, une relation parent-enfant se crée. La liste des modules affiche trois cartes :
1<!-- ModuleList.vue (PARENT) -->
2<template>
3 <div class="module-list">
4 <h2>Modules de la station</h2>
5 <!-- ModuleCard est un ENFANT de ModuleList -->
6 <ModuleCard />
7 <ModuleCard />
8 <ModuleCard />
9 </div>
10</template>
11
12<script setup>
13import ModuleCard from './ModuleCard.vue'
14</script>Dans cet exemple :
ModuleListest le parent- Chaque
ModuleCardest un enfant Appest le parent deModuleList- une hiérarchie se forme
Les rôles sont relatifs : ModuleList est l'enfant de App et en même temps le parent des cartes. Si chaque carte affichait encore un composant ModulePanel, celui-ci serait un petit-enfant de ModuleList, et App deviendrait le grand-parent des cartes.
L'arbre de composants
Chaque application Vue crée un arbre de composants - une structure hiérarchique qui part du composant racine (App.vue) et que tu verras aussi dans l'onglet Components des DevTools :
1App
2├── StationHeader
3│ ├── Logo
4│ └── NavigationMenu
5│ ├── NavItem (Dashboard)
6│ ├── NavItem (Modules)
7│ └── NavItem (Settings)
8├── ModuleList
9│ ├── ModuleCard (Oxygen Generator)
10│ ├── ModuleCard (Plasma Core)
11│ └── ModuleCard (Water Recycler)
12├── ControlPanel
13│ ├── StatusDisplay
14│ └── ActionButtons
15└── StationFooterPlus on descend dans l'arbre, plus le composant est spécialisé. App est la structure générale, tandis que NavItem est un élément de menu précis.
L'imbrication des composants
Les composants peuvent contenir d'autres composants sur n'importe quelle profondeur. Le panneau de commande se compose d'un afficheur de statut et de trois boutons :
1<!-- ControlPanel.vue -->
2<template>
3 <section class="control-panel">
4 <StatusDisplay />
5 <div class="actions">
6 <ActionButton label="Launch" icon="play" />
7 <ActionButton label="Stop" icon="stop" />
8 <ActionButton label="Restart" icon="refresh" />
9 </div>
10 </section>
11</template>
12
13<script setup>
14import StatusDisplay from './StatusDisplay.vue'
15import ActionButton from './ActionButton.vue'
16</script>L'afficheur de statut est un niveau d'imbrication de plus, car il se compose lui-même de trois indicateurs distincts de l'état de la station :
1<!-- StatusDisplay.vue - un autre niveau d'imbrication -->
2<template>
3 <div class="status">
4 <StatusIndicator label="Energy" value="87%" color="green" />
5 <StatusIndicator label="Oxygen" value="95%" color="green" />
6 <StatusIndicator label="Temperature" value="22°C" color="yellow" />
7 </div>
8</template>
9
10<script setup>
11import StatusIndicator from './StatusIndicator.vue'
12</script>Les attributs label, value et color sont des données que le parent transmet à l'enfant. Pour que l'enfant puisse les recevoir, il les déclare avec la macro defineProps. Tu n'importes pas cette macro - le compilateur de <script setup> la connaît tout seul. Voici à quoi pourrait ressembler un bouton du panneau de commande :
1<!-- ActionButton.vue -->
2<template>
3 <button class="action">{{ label }}</button>
4</template>
5
6<script setup>
7defineProps(['label', 'icon'])
8</script>Chacun des trois boutons affiche désormais sa propre inscription, alors qu'il n'y a qu'un seul fichier de composant. Tu découvriras toute la puissance des props, avec les types et la validation, à la Station de Communication.
Trois étapes pour utiliser un enfant
Quelle que soit la profondeur de l'arbre, utiliser un composant enfant demande toujours les trois mêmes étapes : tu crées un fichier .vue, tu l'importes dans le parent et tu utilises sa balise dans le template du parent. Si tu oublies l'import, Vue ne reconnaîtra pas la balise.
Le flux de données dans l'arbre
Dans l'arbre de composants de Vue, les données circulent dans des directions précises :
- Vers le bas (parent → enfant) : via les props - le parent transmet des données à ses enfants
- Vers le haut (enfant → parent) : via les événements - l'enfant informe le parent de ce qui se passe
Ce modèle s'appelle le flux de données unidirectionnel (one-way data flow). Tu découvriras les détails des props et des événements dans le prochain module - pour l'instant, retiens les directions :
1 App (données)
2 │
3 ▼ props (vers le bas)
4 ModuleList
5 │
6 ▼ props (vers le bas)
7 ModuleCard
8 │
9 ▲ événements (vers le haut)
10 ModuleList
11 │
12 ▲ événements (vers le haut)
13 App (réagit)Un enfant ne modifie pas directement les données du parent - les props sont en lecture seule pour lui - mais il signale un événement, et c'est le parent qui décide. Grâce à cela, tu sais toujours où chercher la source d'un changement : dans le composant qui possède les données. Dans l'éditeur ci-dessous, tu verras l'arbre App, MarsBase, MarsModule et ModuleDetail, construit exactement de cette façon.
Retiens ceci : la station est un arbre de modules - chaque composant fait une seule chose, le parent assemble ses enfants en un tout, et les données descendent tandis que les événements remontent.
Code de cette leçon : App.vue
1<script setup>
2import MarsBase from './MarsBase.vue'
3</script>
4
5<template>
6 <div class="composition-lab">
7 <div class="header">
8 <h1>Composition de composants - NOVA LAB</h1>
9 <p class="subtitle">Construire une interface complexe à partir de composants</p>
10 </div>
11
12 <div class="info-panel">
13 <h3>La composition de composants</h3>
14 <p>On peut <strong>imbriquer</strong> les composants les uns dans les autres pour créer une hiérarchie :</p>
15 <p>App → MarsBase → MarsModule → ModuleDetail</p>
16 <p>Chaque niveau est responsable de sa partie de l'interface</p>
17 </div>
18
19 <MarsBase />
20 </div>
21</template>
22
23<style scoped>
24.composition-lab {
25 background: linear-gradient(135deg, #0a0e27 0%, #1a1e3f 100%);
26 min-height: 100vh;
27 padding: 2rem;
28 color: #ffffff;
29 font-family: 'Courier New', monospace;
30}
31
32.header {
33 text-align: center;
34 margin-bottom: 2rem;
35 padding-bottom: 1rem;
36 border-bottom: 2px solid #00ff88;
37}
38
39.header h1 {
40 font-size: 2rem;
41 color: #00ff88;
42 text-shadow: 0 0 20px rgba(0, 255, 136, 0.5);
43 margin: 0;
44}
45
46.subtitle {
47 color: #00b4d8;
48 font-size: 1.1rem;
49 margin-top: 0.5rem;
50}
51
52.info-panel {
53 background: rgba(0, 180, 216, 0.1);
54 border: 2px solid #00b4d8;
55 border-radius: 10px;
56 padding: 1.5rem;
57 margin-bottom: 2rem;
58}
59
60.info-panel h3 {
61 color: #00b4d8;
62 margin-top: 0;
63}
64
65.info-panel strong {
66 color: #00ff88;
67}
68</style>Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Qu'est-ce que la composition de composants ?
2. Quelle est la relation entre un composant qui en utilise un autre et celui qui est utilisé ?
Voici 2 des 3 questions de cette leçon. Réponds aux autres dans le jeu.
Tâches pratiques dans le jeu
- Éditeur de code
Crée un MarsBase composé de plusieurs composants MarsModule.
- Tri vertical
Range la hiérarchie des composants de la racine jusqu'au plus profond :
- Clique dans l'ordre
Range les étapes pour utiliser un composant enfant :