Cours Vue.js · Module 6: Composants
Projet : Mars Dashboard
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.vuedistinct 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
scopedsur 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.