Cours Vue.js · Module 6: Composants

Projet : Mars Dashboard

3 min de lecture
Dans cette leçon2

Projet final de la Baie d'Impression 3D ! Construis un tableau de bord complet de la station NOVA LAB avec plusieurs composants, cycles de vie et composables.

Récapitulatif du module

Dans ce module, tu as appris les fondamentaux de la construction d'applications Vue.js à partir de composants - tout comme la station NOVA LAB est composée de modules d'habitat, ton application est composée de composants :

  • Composants - créer des éléments d'interface autonomes et réutilisables, avec leur propre template (<template>), leur logique (<script setup>) et leurs styles (<style>). Chaque composant est un fichier .vue distinct avec une responsabilité clairement définie
  • Import de composants - enregistrement local (import dans un composant donné) et enregistrement global (disponible dans toute l'application via app.component()). Avec la Composition API et <script setup>, les composants importés sont automatiquement disponibles dans le template
  • Composition - construire des interfaces complexes à partir de composants simples et plus petits. Le modèle parent-enfant, transmettre les données vers le bas et émettre des événements vers le haut de l'arbre de composants
  • Lifecycle hooks - onMounted (après insertion dans le DOM), onUpdated (après mise à jour), onUnmounted (après le retrait), onBeforeMount, onBeforeUpdate - permettent d'exécuter du code aux moments clés de la vie d'un composant
  • Styles scoped - isolation des styles dans les composants via l'attribut scoped sur la balise <style>. Les styles sont automatiquement limités au composant concerné et n'affectent pas le reste de l'application
  • Composables - des fonctions réutilisables (par ex. useTimer, useFetch) qui encapsulent un état réactif et de la logique. Elles permettent de partager de la logique entre composants sans dupliquer le code

Exigences du projet

Construis un Mars Dashboard - le tableau de bord central de la station NOVA LAB, composé de plusieurs composants qui coopèrent :

1. Composant StatusBar

Affiche l'état général de la station : nom de la station, date et heure actuelles (mises à jour chaque seconde via un composable), niveau d'énergie (barre de progression), température extérieure et pression de l'habitat. Utilise onMounted pour l'initialisation des données et onUnmounted pour le nettoyage du timer.

2. Composant ModuleList

Une liste de modules d'habitat (par ex. Oxygen Generator, Water Recycler, Solar Panels, Communication Array) avec la possibilité de basculer l'état de chaque module (ACTIVE/STANDBY/OFFLINE). Chaque module doit être rendu comme un composant ModuleCard distinct, avec des couleurs de statut appropriées.

3. Composable useTimer

Crée un composable useTimer qui compte le temps écoulé depuis le démarrage de l'application (uptime de la mission). Utilise ref pour l'état, onMounted pour lancer setInterval, et onUnmounted pour effacer l'intervalle (clearInterval). Le composable doit renvoyer un temps formaté (HH:MM:SS).

4. Styles scoped

Chaque composant doit avoir ses propres styles isolés avec l'attribut scoped. Utilise un thème spatial sombre (fonds sombres, couleurs d'accent néon : vert pour ACTIVE, jaune pour STANDBY, rouge pour OFFLINE). Veille à la responsivité - le tableau de bord doit fonctionner sur différentes tailles d'écran.

Complète le starter ci-dessous !

Code de cette leçon : App.vue
1<script setup>
2import { ref, onMounted, onUnmounted } from 'vue'
3
4// Mars Dashboard - Projet final du module 6
5// Démonstration des composants, lifecycle hooks et composables
6
7// Composable : useTimer
8function useTimer() {
9  const elapsed = ref(0)
10  let interval = null
11
12  onMounted(() => {
13    interval = setInterval(() => { elapsed.value++ }, 1000)
14  })
15
16  onUnmounted(() => {
17    if (interval) clearInterval(interval)
18  })
19
20  const formatted = ref('')
21  setInterval(() => {
22    const h = Math.floor(elapsed.value / 3600)
23    const m = Math.floor((elapsed.value % 3600) / 60)
24    const s = elapsed.value % 60
25    formatted.value = [h, m, s].map(v => String(v).padStart(2, '0')).join(':')
26  }, 1000)
27
28  return { elapsed, formatted }
29}
30
31const { formatted: uptime } = useTimer()
32
33const stationName = ref('NOVA LAB Mars Base')
34const energyLevel = ref(87)
35
36const modules = ref([
37  { id: 1, name: 'Laboratoire', status: true },
38  { id: 2, name: 'Réacteur', status: true },
39  { id: 3, name: 'Communication', status: false },
40  { id: 4, name: 'Serre', status: true },
41  { id: 5, name: 'Atelier', status: true }
42])
43
44function toggleModule(id) {
45  const mod = modules.value.find(m => m.id === id)
46  if (mod) mod.status = !mod.status
47}
48
49// TODO : Extrais StatusBar et ModuleList dans des composants séparés
50// TODO : Ajoute des styles scoped à chaque composant
51// TODO : Enrichis le composable useTimer avec start/stop
52</script>
53
54<template>
55  <div class="mars-dashboard">
56    <!-- StatusBar -->
57    <header class="status-bar">
58      <h1>{{ stationName }}</h1>
59      <div class="info">
60        <span>Uptime : {{ uptime }}</span>
61        <span>Énergie : {{ energyLevel }}%</span>
62      </div>
63    </header>
64
65    <!-- ModuleList -->
66    <section class="module-list">
67      <h2>Modules de l'habitat</h2>
68      <div
69        v-for="mod in modules"
70        :key="mod.id"
71        class="module-item"
72        :class="{ online: mod.status, offline: !mod.status }"
73        @click="toggleModule(mod.id)"
74      >
75        <span class="dot"></span>
76        <span>{{ mod.name }}</span>
77        <span class="tag">{{ mod.status ? 'ONLINE' : 'OFFLINE' }}</span>
78      </div>
79    </section>
80  </div>
81</template>
82
83<style scoped>
84.mars-dashboard { background: #0a0a2e; color: #e0e0ff; padding: 2rem; min-height: 100vh; font-family: monospace; }
85.status-bar { border-bottom: 1px solid #333; padding-bottom: 1rem; margin-bottom: 1rem; }
86.status-bar h1 { color: #ff6b35; margin: 0; }
87.info { display: flex; gap: 2rem; color: #888; margin-top: 0.5rem; }
88.module-list h2 { color: #00d4ff; }
89.module-item { display: flex; align-items: center; gap: 1rem; padding: 0.8rem; margin: 0.5rem 0; border-radius: 4px; cursor: pointer; background: #1a1a4e; }
90.module-item.online { border-left: 3px solid #00ff88; }
91.module-item.offline { border-left: 3px solid #ff4444; opacity: 0.7; }
92.dot { width: 8px; height: 8px; border-radius: 50%; }
93.online .dot { background: #00ff88; }
94.offline .dot { background: #ff4444; }
95.tag { margin-left: auto; font-size: 0.8rem; }
96</style>

Tu as repéré une erreur dans cette leçon ?

Tâches pratiques dans le jeu

  • Éditeur de code

    Construis un MarsDashboard avec plusieurs composants, composables, lifecycle hooks et styles scoped.