Cours Vue.js · Module 2: Syntaxe des templates
Liaison de classes et de styles
Dans cette leçon4
Tout comme les systèmes du NOVA LAB adaptent les hologrammes à la situation, Vue te permet de gérer dynamiquement les styles de l'interface.
Le panneau de statut doit briller en vert quand le système fonctionne et pulser en rouge en cas de panne. Avec un simple v-bind, tu devrais coller les noms de classes dans une chaîne, par exemple 'panel ' + (isOnline ? 'active' : ''), et avec trois conditions une telle écriture devient illisible. C'est pourquoi :class et :style ont des pouvoirs spéciaux dans Vue : ils acceptent non seulement du texte, mais aussi des objets et des tableaux.
Liaison de classe - Syntaxe objet
Dans la syntaxe objet, la clé est le nom de la classe et la valeur une condition : quand elle est vraie, la classe est ajoutée à l'élément. Les noms avec un tiret, comme 'status-critical', s'écrivent entre guillemets. :class peut côtoyer un attribut class ordinaire - les classes fixes restent et les classes dynamiques s'y ajoutent.
1<template>
2 <div class="status-panel" style="background: #0a0e27;">
3 <div :class="{ active: isOnline, 'status-critical': hasCriticalError }">
4 System Status Display
5 </div>
6
7 <!-- Avec computed -->
8 <div :class="statusClasses">Computed Status</div>
9 </div>
10</template>Avec isOnline à true et sans panne, le premier div intérieur reçoit seulement la classe active, et celui de l'extérieur garde son status-panel. Le second div prend un objet de classes tout prêt dans la variable statusClasses, qui est une propriété computed.
Une propriété computed est une valeur calculée : tu fournis une fonction, et Vue mémorise son résultat et ne le recalcule que lorsque les refs utilisés à l'intérieur changent. Tu la lis comme un ref, et tu découvriras les détails dans le module 4. Ici, elle renvoie un objet de classes :
1<script setup>
2import { ref, computed } from 'vue'
3
4const isOnline = ref(true)
5const hasCriticalError = ref(false)
6
7const statusClasses = computed(() => ({
8 active: isOnline.value,
9 'status-critical': hasCriticalError.value,
10 'neon-glow': isOnline.value
11}))
12</script>Quand tu règles hasCriticalError.value = true, l'objet se recalcule tout seul et le panneau reçoit la classe status-critical. La documentation de Vue qualifie ce modèle de courant et puissant. Mon choix : un objet directement dans le template pour une ou deux classes, une computed pour davantage de conditions. Les classes elles-mêmes sont définies par du CSS ordinaire :
1<style>
2.active {
3 color: #00ff88;
4 border-left: 3px solid #00ff88;
5}
6.status-critical {
7 color: #ff4444;
8 animation: pulse 1s infinite;
9}
10.neon-glow {
11 box-shadow: 0 0 10px #00ff88;
12}
13@keyframes pulse {
14 0%, 100% { opacity: 1; }
15 50% { opacity: 0.5; }
16}
17</style>Vue décide uniquement quels noms de classes se retrouvent dans l'attribut class. L'apparence, l'animation pulse et le halo restent l'affaire du CSS, exactement comme dans le premier monde.
Liaison de classe - Syntaxe tableau
Un tableau est pratique quand les noms de classes se trouvent eux-mêmes dans des variables. Ses éléments sont des expressions, donc tu peux y utiliser l'opérateur conditionnel ou y placer un objet de la section précédente :
1<template>
2 <div class="reactor-display">
3 <div :class="[activeClass, statusClass]">
4 Array syntax
5 </div>
6
7 <!-- Avec condition -->
8 <div :class="[isOnline ? 'online' : 'offline', statusClass]">
9 Conditional class
10 </div>
11
12 <!-- Mixte -->
13 <div :class="[{ active: isOnline }, statusClass]">
14 Mixed
15 </div>
16 </div>
17</template>
18
19<script setup>
20import { ref } from 'vue'
21
22const activeClass = ref('reactor-active')
23const statusClass = ref('status-nominal')
24const isOnline = ref(true)
25</script>Le premier div reçoit les classes reactor-active status-nominal, le deuxième online status-nominal et le troisième active status-nominal. Le tableau contient les valeurs des variables, pas leurs noms : activeClass désigne la chaîne reactor-active. Quand un ternaire avec une chaîne vide apparaît dans le tableau, choisis la version mixte avec un objet - elle est plus courte et plus lisible.
Liaison de style inline
:style accepte un objet de propriétés CSS. Les clés en camelCase comme fontSize sont recommandées, même si les clés avec tiret entre guillemets fonctionnent aussi. Les nombres ont besoin d'une unité, c'est pourquoi on ajoute 'px'. Tu peux aussi passer un objet de styles tout prêt ou un tableau d'objets :
1<template>
2 <div class="hologram-container">
3 <!-- Syntaxe objet -->
4 <div :style="{ color: neonColor, fontSize: fontSize + 'px' }">
5 Inline styles
6 </div>
7
8 <!-- Avec un objet -->
9 <div :style="panelStyle">Style object</div>
10
11 <!-- Syntaxe tableau - plusieurs objets -->
12 <div :style="[baseStyles, highlightStyles]">
13 Multiple style objects
14 </div>
15 </div>
16</template>Le premier div reçoit color et font-size: 18px. Dans un tableau, les objets fusionnent en un seul, et quand une propriété se répète, la dernière l'emporte. Les données viennent du script :
1<script setup>
2import { ref, reactive } from 'vue'
3
4const neonColor = ref('#00ff88')
5const fontSize = ref(18)
6
7const panelStyle = reactive({
8 color: '#00b4d8',
9 backgroundColor: '#0a0e27',
10 padding: '1rem',
11 borderRadius: '8px',
12 border: '1px solid #00ff88'
13})
14
15const baseStyles = { color: '#00b4d8' }
16const highlightStyles = { fontSize: '20px', textShadow: '0 0 10px #00b4d8' }
17</script>Changer fontSize.value = 24 n'agrandit que le texte du premier div. baseStyles et highlightStyles sont de simples objets non réactifs, donc les modifier plus tard ne rafraîchira pas la vue - comme constantes, ils fonctionnent pourtant parfaitement.
Quand un style dépend de plusieurs conditions, prépare l'objet dans une computed, comme pour les classes :
1<script setup>
2import { ref, computed } from 'vue'
3
4const oxygenLevel = ref(18)
5
6const alertStyle = computed(() => ({
7 color: oxygenLevel.value < 20 ? '#ff4444' : '#00ff88',
8 fontWeight: oxygenLevel.value < 20 ? 'bold' : 'normal'
9}))
10</script>
11
12<template>
13 <p :style="alertStyle">Oxygène : {{ oxygenLevel }}%</p>
14</template>Le template ne garde qu'une liaison courte, et toute la logique vit dans le script. Malgré tout je te recommande les classes plutôt que les styles inline partout où l'apparence est connue à l'avance. Réserve :style aux valeurs vraiment calculées à partir des données, comme la largeur d'une barre d'énergie.
Préfixage automatique
Vue sait ajouter les préfixes des navigateurs, mais il le fait avec parcimonie : pendant l'exécution, il vérifie si le navigateur actuel connaît une propriété donnée, et seulement s'il ne la connaît pas, il essaie les variantes préfixées :
1<div :style="{ transform: 'rotateX(45deg)' }">
2 <!-- Vue ajoute un préfixe (ex. -webkit-) seulement si le navigateur ne connaît pas la version sans préfixe -->
3</div>Les navigateurs modernes connaissent transform, tu le verras donc sans préfixe. Tu peux aussi passer un tableau de valeurs, par exemple ['-webkit-box', 'flex'] pour display - Vue utilise la dernière valeur prise en charge. Dans la prochaine leçon, tu décideras si un élément doit même exister, grâce à v-if et v-show.
Retiens : l'objet dans :class est un tableau d'interrupteurs - la clé est le nom de la classe, et la valeur décide si le voyant s'allume.
Code de cette leçon : App.vue
1<script setup>
2import { ref, computed } from 'vue'
3
4const isOnline = ref(true)
5const hasCriticalError = ref(false)
6const modeClass = ref('mode-nominal')
7const neonColor = ref('#00ff88')
8const fontSize = ref(18)
9const oxygenLevel = ref(18)
10
11// objet de styles calculé à partir des données : texte rouge et gras quand l’oxygène manque
12const alertStyle = computed(() => ({
13 color: oxygenLevel.value < 20 ? '#ff4444' : '#00ff88',
14 fontWeight: oxygenLevel.value < 20 ? 'bold' : 'normal'
15}))
16</script>
17
18<template>
19 <div class="hologram-lab">
20 <h1>Atelier des hologrammes : classes et styles</h1>
21
22 <div class="controls">
23 <button @click="isOnline = !isOnline">Basculer l’alimentation</button>
24 <button @click="hasCriticalError = !hasCriticalError">Simuler une panne</button>
25 <button @click="fontSize += 2">Texte plus grand</button>
26 <button @click="oxygenLevel += 5">Ajouter de l’oxygène</button>
27 </div>
28
29 <!-- Syntaxe objet : la clé est le nom de la classe, la valeur est la condition -->
30 <div class="panel" :class="{ active: isOnline, 'status-critical': hasCriticalError }">
31 Statut du système : {{ isOnline ? 'EN LIGNE' : 'HORS LIGNE' }}
32 </div>
33
34 <!-- Syntaxe tableau : des noms de classes venant d’une variable et d’un ternaire -->
35 <div class="panel" :class="[modeClass, isOnline ? 'online' : 'offline']">
36 Mode de fonctionnement depuis un tableau de classes
37 </div>
38
39 <!-- Syntaxe mixte : un objet dans le tableau -->
40 <div class="panel" :class="[{ active: isOnline }, modeClass]">
41 Mode mixte
42 </div>
43
44 <!-- :style avec un objet : clés en camelCase, nombre avec l’unité px -->
45 <p :style="{ color: neonColor, fontSize: fontSize + 'px' }">
46 Taille du texte : {{ fontSize }}px
47 </p>
48
49 <!-- :style avec computed : la logique reste dans le script -->
50 <p :style="alertStyle">Oxygène : {{ oxygenLevel }}%</p>
51 </div>
52</template>
53
54<style scoped>
55.hologram-lab { background: #0a0e27; color: #e0e0ff; min-height: 100vh; padding: 1.5rem; font-family: 'Courier New', monospace; }
56h1 { color: #00b4d8; font-size: 1.4rem; }
57.controls { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem; }
58button { background: transparent; border: 2px solid #00ff88; color: #00ff88; padding: 0.4rem 0.8rem; cursor: pointer; font-family: inherit; }
59.panel { border: 2px solid #334; border-radius: 8px; padding: 0.75rem; margin: 0.5rem 0; }
60.active { color: #00ff88; border-left: 4px solid #00ff88; }
61.status-critical { color: #ff4444; animation: pulse 1s infinite; }
62.online { box-shadow: 0 0 10px #00ff88; }
63.offline { opacity: 0.5; }
64.mode-nominal { border-color: #00b4d8; }
65@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
66</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. Comment ajoutes-tu conditionnellement une classe CSS dans Vue ?
2. Comment affectes-tu plusieurs classes dynamiquement à l'aide d'un tableau ?
3. Comment définis-tu dynamiquement la couleur du texte dans Vue ?
Tâches pratiques dans le jeu
- Éditeur de code
Utilise :class avec la syntaxe objet et la syntaxe tableau pour ajouter conditionnellement des classes.
- Clique dans l'ordre
Ordonne la syntaxe de style inline dynamique :
- Tri horizontal
Ordonne la syntaxe correcte pour une liaison de classe conditionnelle :
- Tri vertical
Ordonne les méthodes de liaison de classe de la plus simple à la mixte :
- Éditeur de code
Utilise :style pour définir dynamiquement les couleurs et la taille de police.