Kurs Vue.js · Moduł 2: Składnia szablonów

Wiązanie Klas i Stylów

5 min czytania
W tej lekcji4

Jak systemy NOVA LAB dostosowują hologramy do sytuacji, tak Vue pozwala dynamicznie zarządzać stylami interfejsu.

Panel statusu ma świecić na zielono, gdy system działa, i pulsować na czerwono przy awarii. Z samym v-bind musiałbyś sklejać nazwy klas w stringu, na przykład 'panel ' + (isOnline ? 'active' : ''), a przy trzech warunkach taki zapis staje się nieczytelny. Dlatego :class i :style mają w Vue specjalne uprawnienia: przyjmują nie tylko tekst, ale też obiekty i tablice.

Wiązanie Klas - Składnia Obiektowa

W składni obiektowej klucz to nazwa klasy, a wartość to warunek: gdy jest prawdziwy, klasa trafia do elementu. Nazwy z myślnikiem, jak 'status-critical', piszesz w cudzysłowie. :class może stać obok zwykłego atrybutu class - klasy stałe zostają, a dynamiczne są dopisywane.

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    <!-- Z computed -->
8    <div :class="statusClasses">Computed Status</div>
9  </div>
10</template>

Przy isOnline równym true i braku awarii pierwszy wewnętrzny div dostanie tylko klasę active, a zewnętrzny zachowa swoje status-panel. Drugi div bierze gotowy obiekt klas ze zmiennej statusClasses, która jest właściwością computed.

Computed to wartość wyliczana: podajesz funkcję, a Vue zapamiętuje jej wynik i liczy go ponownie tylko wtedy, gdy zmienią się refy użyte w środku. Czytasz ją jak ref, a szczegóły poznasz w module 4. Tutaj zwraca obiekt klas:

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>

Gdy ustawisz hasCriticalError.value = true, obiekt przeliczy się sam i panel dostanie klasę status-critical. Dokumentacja Vue nazywa ten wzorzec częstym i bardzo użytecznym. Mój wybór: obiekt wprost w szablonie dla jednej lub dwóch klas, computed przy większej liczbie warunków. Same klasy definiuje zwykły CSS:

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 decyduje wyłącznie o tym, które nazwy klas trafią do atrybutu class. Wygląd, animacja pulse i poświata pozostają sprawą CSS, dokładnie jak w pierwszym świecie.

Wiązanie Klas - Składnia Tablicowa

Tablica przydaje się, gdy nazwy klas same siedzą w zmiennych. Jej elementy to wyrażenia, więc możesz w nich użyć operatora warunkowego albo wstawić obiekt z poprzedniej sekcji:

1<template>
2  <div class="reactor-display">
3    <div :class="[activeClass, statusClass]">
4      Array syntax
5    </div>
6
7    <!-- Z warunkiem -->
8    <div :class="[isOnline ? 'online' : 'offline', statusClass]">
9      Warunkowa klasa
10    </div>
11
12    <!-- Mieszane -->
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>

Pierwszy div dostanie klasy reactor-active status-nominal, drugi online status-nominal, a trzeci active status-nominal. W tablicy stoją wartości zmiennych, nie ich nazwy: activeClass oznacza napis reactor-active. Gdy w tablicy pojawia się ternary z pustym stringiem, wybieraj wersję mieszaną z obiektem - jest krótsza i czytelniejsza.

Wiązanie Stylów Inline

:style przyjmuje obiekt właściwości CSS. Zalecane są klucze w camelCase, jak fontSize, choć klucze z myślnikiem w cudzysłowie też działają. Liczby potrzebują jednostki, dlatego dopisujemy 'px'. Możesz też podać gotowy obiekt stylów albo tablicę obiektów:

1<template>
2  <div class="hologram-container">
3    <!-- Składnia obiektowa -->
4    <div :style="{ color: neonColor, fontSize: fontSize + 'px' }">
5      Inline styles
6    </div>
7
8    <!-- Z obiektem -->
9    <div :style="panelStyle">Style object</div>
10
11    <!-- Składnia tablicowa - wiele obiektów -->
12    <div :style="[baseStyles, highlightStyles]">
13      Multiple style objects
14    </div>
15  </div>
16</template>

Pierwszy div dostanie color i font-size: 18px. W tablicy obiekty łączą się w jeden, a przy powtórzonej właściwości wygrywa późniejszy. Dane pochodzą ze skryptu:

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>

Zmiana fontSize.value = 24 powiększy tylko tekst pierwszego div. baseStyles i highlightStyles to zwykłe obiekty, nie reaktywne, więc ich późniejsza zmiana nie odświeży widoku - jako stałe sprawdzają się jednak bez zarzutu.

Gdy styl zależy od kilku warunków, przygotuj obiekt w computed, tak jak przy klasach:

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">Tlen: {{ oxygenLevel }}%</p>
14</template>

W szablonie zostało jedno krótkie wiązanie, a cała logika mieszka w skrypcie. Mimo to polecam klasy zamiast stylów inline wszędzie, gdzie wygląd jest znany z góry. :style zostaw dla wartości naprawdę liczonych z danych, jak szerokość paska mocy.

Auto-prefixing

Vue potrafi dodawać prefiksy producentów przeglądarek, ale robi to oszczędnie: w trakcie działania sprawdza, czy bieżąca przeglądarka zna daną właściwość, i tylko gdy jej nie zna, próbuje wariantów z prefiksem:

1<div :style="{ transform: 'rotateX(45deg)' }">
2  <!-- Vue doda prefiks (np. -webkit-) tylko wtedy, gdy przeglądarka nie zna wersji bez prefiksu -->
3</div>

Współczesne przeglądarki znają transform, więc zobaczysz go bez prefiksu. Możesz też podać tablicę wartości, na przykład ['-webkit-box', 'flex'] dla display - Vue użyje ostatniej obsługiwanej. W następnej lekcji zdecydujesz, czy element w ogóle ma istnieć, dzięki v-if i v-show.

Zapamiętaj: obiekt w :class to tablica przełączników - klucz to nazwa klasy, a wartość decyduje, czy lampka świeci.

Kod do tej lekcji: 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// obiekt stylów liczony z danych: czerwony i pogrubiony tekst, gdy tlenu jest za mało
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>Pracownia Hologramów: klasy i style</h1>
21
22    <div class="controls">
23      <button @click="isOnline = !isOnline">Przełącz zasilanie</button>
24      <button @click="hasCriticalError = !hasCriticalError">Symuluj awarię</button>
25      <button @click="fontSize += 2">Większy tekst</button>
26      <button @click="oxygenLevel += 5">Dodaj tlen</button>
27    </div>
28
29    <!-- Składnia obiektowa: klucz to nazwa klasy, wartość to warunek -->
30    <div class="panel" :class="{ active: isOnline, 'status-critical': hasCriticalError }">
31      Status systemu: {{ isOnline ? 'ONLINE' : 'OFFLINE' }}
32    </div>
33
34    <!-- Składnia tablicowa: nazwy klas ze zmiennej i z operatora warunkowego -->
35    <div class="panel" :class="[modeClass, isOnline ? 'online' : 'offline']">
36      Tryb pracy z tablicy klas
37    </div>
38
39    <!-- Składnia mieszana: obiekt wewnątrz tablicy -->
40    <div class="panel" :class="[{ active: isOnline }, modeClass]">
41      Tryb mieszany
42    </div>
43
44    <!-- :style z obiektem: klucze w camelCase, liczba z jednostką px -->
45    <p :style="{ color: neonColor, fontSize: fontSize + 'px' }">
46      Rozmiar tekstu: {{ fontSize }}px
47    </p>
48
49    <!-- :style z computed: logika zostaje w skrypcie -->
50    <p :style="alertStyle">Tlen: {{ 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>

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Jak warunkowo dodać klasę CSS w Vue?

  2. 2. Jak przypisać wiele klas dynamicznie przez array?

  3. 3. Jak dynamicznie ustawić kolor tekstu w Vue?

Zadania praktyczne w grze

  • Edytor kodu

    Użyj :class ze składnią obiektową i tablicową, aby warunkowo dodawać klasy.

  • Klikanie w kolejności

    Ułóż składnię dynamicznego stylu inline:

  • Układanie w poziomie

    Ułóż poprawną składnię bindowania klasy warunkowej:

  • Układanie w pionie

    Ułóż sposoby wiązania klas od prostego do mieszanego:

  • Edytor kodu

    Użyj :style do dynamicznego ustawienia kolorów i rozmiaru czcionki.

Przydatne artykuły