Cours Vue.js · Module 8: Slots et composants dynamiques

Les slots - les bases

6 min de lecture
Dans cette leçon6

Bienvenue dans le Stockage de Modules du NOVA LAB ! Ici, chaque conteneur de fret possède des ports d'amarrage standardisés - tu peux y brancher des contenus différents tout en conservant la même structure extérieure. Avant de découvrir le mécanisme, ressens le problème : tu construis un composant CargoBay avec un cadre, un en-tête et une bordure. Une soute contient des réservoirs d'oxygène, une autre une liste de filtres, une troisième tout un panneau d'état. Les props transportent très bien un titre ou un nombre, mais elles ne peuvent pas transporter un morceau de template avec de la mise en forme et d'autres composants. Sans nouvel outil, tu devrais copier CargoBay pour chaque type de fret. En Vue, cet outil, ce sont les slots - ils permettent à un parent d'injecter un contenu arbitraire dans un composant enfant.

Ce que tu vas apprendre

Dans le Stockage de Modules, tu vas maîtriser tout le système d'amarrage des composants :

  • insérer du contenu dans un composant grâce au slot par défaut et lui donner un contenu de repli,
  • découper un composant en plusieurs ports grâce aux slots nommés,
  • transmettre des données de l'enfant vers le contenu du slot grâce aux scoped slots,
  • basculer entre les panneaux de la station avec <component :is> et conserver leur état dans <KeepAlive>,
  • afficher des alarmes en dehors de la hiérarchie des composants avec <Teleport>,
  • charger des modules lourds à la demande avec les composants asynchrones et <Suspense>.

Qu'est-ce qu'un slot ?

Un slot est un emplacement dans le template d'un composant enfant que le parent peut remplir avec son propre contenu. C'est comme un port d'amarrage dans une soute à fret - le composant définit où se trouve l'ouverture, et le parent décide de ce qu'il y met. La documentation de Vue appelle la balise <slot> une sortie de slot (slot outlet), et ce que transmet le parent, le contenu du slot. Ci-dessous, tu vois d'abord l'enfant, CargoBay.vue, puis le parent, App.vue, qui place deux paragraphes entre les balises du composant :

1<!-- CargoBay.vue (enfant) -->
2<template>
3  <div class="cargo-bay">
4    <h2>Cargo Bay Alpha</h2>
5    <div class="content">
6      <slot></slot>
7    </div>
8  </div>
9</template>
10
11<!-- App.vue (parent) -->
12<template>
13  <CargoBay>
14    <p>Oxygen Tank OX-2087</p>
15    <p>Weight: 250 kg</p>
16  </CargoBay>
17</template>

Le parent place le contenu entre les balises du composant, et ce contenu va là où se trouve <slot></slot>. Le cadre, l'en-tête "Cargo Bay Alpha" et les classes CSS n'ont pas bougé d'un pixel - CargoBay ne sait pas ce qu'il transporte, et il n'a pas besoin de le savoir.

Comment Vue rend un slot

Il vaut la peine de comprendre ce qui se passe sous le capot, car cela explique le comportement des slots dans les leçons suivantes. Tout le processus se déroule en quatre étapes :

  1. Le composant enfant définit <slot> dans son template - c'est le port d'amarrage.
  2. Le composant parent transmet du contenu entre les balises de l'enfant.
  3. Quand Vue rend l'enfant, il remplace <slot> par le contenu transmis. Techniquement, le compilateur transforme le contenu du parent en fonction, et l'enfant l'appelle exactement à l'emplacement de la sortie.
  4. Le contenu apparaît dans le DOM à l'emplacement du slot, chez nous à l'intérieur de div.content.

La balise <slot> elle-même ne reste pas dans le HTML final - dans le navigateur, tu ne vois que les paragraphes du parent à l'intérieur du cadre de l'enfant.

Contenu de repli (fallback)

Et si le parent laisse le port vide ? Le contenu écrit entre <slot> et </slot> dans l'enfant est un contenu de repli (fallback), et il ne s'affiche que lorsque le parent ne transmet rien :

1<!-- CargoBay.vue -->
2<template>
3  <div class="cargo-bay">
4    <slot>
5      <p>Soute vide - en attente d'équipement</p>
6    </slot>
7  </div>
8</template>
9
10<!-- Utilisation sans contenu - affiche le fallback -->
11<CargoBay />
12
13<!-- Utilisation avec contenu - remplace le fallback -->
14<CargoBay>
15  <p>Water Recycler Unit</p>
16</CargoBay>

La première utilisation affiche le message de soute vide, et la deuxième le remplace entièrement par la description du recycleur d'eau. Le fallback ne se mélange jamais au contenu du parent : l'écran affiche soit l'un, soit l'autre.

La portée du slot

Le contenu du slot est compilé dans la portée du parent, pas dans celle de l'enfant. Cela signifie qu'à l'intérieur du contenu du slot, tu as accès aux données du parent, comme dans cet exemple avec la variable moduleName déclarée dans App.vue :

1<!-- App.vue -->
2<script setup>
3import { ref } from 'vue'
4const moduleName = ref('Oxygen Generator')
5</script>
6
7<template>
8  <CargoBay>
9    <!-- moduleName vient du PARENT -->
10    <p>{{ moduleName }}</p>
11  </CargoBay>
12</template>

Vue cherche moduleName là où le contenu a été écrit, c'est-à-dire dans App.vue. Cela fonctionne aussi dans l'autre sens : le contenu du slot ne voit pas les données de l'enfant, donc une variable déclarée dans CargoBay y serait inaccessible. Tu découvriras comment afficher malgré tout les données de l'enfant dans un slot dans la leçon sur les scoped slots.

Plusieurs éléments dans un slot

Tu peux placer autant d'éléments que tu veux dans un même port : un titre, une liste, et même un autre composant, comme StatusBadge qui affiche le badge d'état du fret :

1<template>
2  <CargoBay>
3    <h3>Critical Equipment</h3>
4    <ul>
5      <li>Oxygen Tank</li>
6      <li>Water Filter</li>
7    </ul>
8    <StatusBadge status="loaded" />
9  </CargoBay>
10</template>

Tout ce qui se trouve entre les balises va dans un seul slot par défaut, dans l'ordre où tu l'as écrit. Quand tu voudras répartir le contenu à plusieurs endroits, par exemple l'en-tête d'un côté et les boutons de l'autre, tu auras besoin des slots nommés de la prochaine leçon.

Mon conseil : quand un composant doit afficher le contenu de quelqu'un d'autre - du texte mis en forme, des boutons, d'autres composants - utilise un slot, pas une prop de type chaîne. Garde les props pour les valeurs simples, comme un titre ou un nombre. Et donne toujours au slot un fallback pertinent, car une soute vide sans message ressemble à une panne. Dans l'éditeur ci-dessous, CargoBay apparaît trois fois : avec la description d'un réservoir, avec une liste de modules et complètement vide, pour que tu voies le fallback en action.

Retiens : un slot est un port d'amarrage - le composant fournit le cadre, et le parent décide quel fret y brancher.

Code de cette leçon : App.vue
1<script setup>
2import CargoBay from './CargoBay.vue'
3</script>
4
5<template>
6  <div class="nova-lab">
7    <h1>NOVA LAB - Démo des slots</h1>
8
9    <!-- Slot avec contenu -->
10    <CargoBay>
11      <h3>Réservoir d'oxygène OX-2087</h3>
12      <p>Poids : 250 kg | Statut : Chargé</p>
13    </CargoBay>
14
15    <!-- Slot avec composant et HTML -->
16    <CargoBay>
17      <ul>
18        <li>Filtre à eau WF-01</li>
19        <li>Cellule solaire SC-44</li>
20        <li>Bouclier thermique TS-12</li>
21      </ul>
22    </CargoBay>
23
24    <!-- Slot vide - affichera le fallback -->
25    <CargoBay />
26  </div>
27</template>
28
29<style scoped>
30.nova-lab {
31  background: #0a0e27;
32  color: #00ff88;
33  min-height: 100vh;
34  padding: 20px;
35  font-family: monospace;
36}
37h1 { color: #00ff88; margin-bottom: 20px; }
38</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. 1. Qu'est-ce qu'un slot dans Vue.js ?

  2. 2. Que se passe-t-il quand un parent ne transmet pas de contenu à un slot qui possède un contenu de repli ?

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 composant CargoBay avec une balise <slot> et un contenu de repli. Utilise-le dans App.vue en y insérant ton propre contenu.

  • Clique dans l'ordre

    Ordonne le code pour utiliser le composant CargoBay avec un contenu de slot :

  • Éditeur de code

    Crée un composant AlertBox avec un slot et un contenu de repli 'Aucune alerte'. Utilise-le une fois avec du contenu et une fois sans.

  • Tri vertical

    Ordonne les étapes du rendu d'un slot, de la définition à l'affichage :