Kurs Vue.js · Moduł 1: Vue i Vite
Single File Components - Moduły Systemu
W tej lekcji5
W NOVA LAB każdy moduł statku jest samodzielną jednostką - ma własne zasilanie, logikę i obudowę. Tak samo Vue Single File Component łączy template, script i style w jednym pliku.
Na klasycznej stronie wygląd panelu leży w pliku HTML, jego zachowanie w pliku JavaScript, a kolory w arkuszu CSS. Żeby poprawić jeden wskaźnik, skaczesz między trzema plikami, a reguła CSS napisana dla jednego panelu potrafi niechcący przemalować drugi. Single File Component, w skrócie SFC, zamyka cały moduł w jednym pliku z rozszerzeniem .vue.
Anatomia Modułu .vue
Przeglądarka nie potrafi otworzyć takiego pliku - plugin Vue skonfigurowany w silniku Vite kompiluje go do zwykłego JavaScriptu i CSS. Rozłożymy teraz na części panel podtrzymywania życia. Trzy bloki kodu poniżej stoją w jednym pliku, jeden pod drugim.
Trzy Sekcje Modułu
1. <template> - Interfejs Użytkownika
- Definiuje co widzi astronauta
- Używa składni Vue (dyrektywy, interpolacja)
- Musi być przejrzysty - w sytuacji kryzysowej nie ma czasu na szukanie
Pierwsza sekcja to szablon: zwykły HTML wzbogacony o składnię Vue, czyli wąsy i atrybuty specjalne poprzedzone dwukropkiem albo małpą:
1<template>
2 <!-- INTERFEJS - co widzi astronauta -->
3 <div class="life-support-panel">
4 <h1>{{ systemName }}</h1>
5 <p>Poziom tlenu: {{ oxygenLevel }}%</p>
6 <div class="status" :class="statusClass">{{ status }}</div>
7 </div>
8</template>Wąsy wyświetlają nazwę systemu, poziom tlenu i status, a zapis :class="statusClass" podpina pod element klasę wyliczaną w skrypcie - dokładnie omówimy go w następnej lekcji. Znaczniki <div>, <h1> i <p> to wciąż ten sam HTML, który znasz z pierwszego świata.
2. <script setup> - Logika Systemu
- Nowoczesna składnia Composition API
- Zmienne, funkcje i importy z najwyższego poziomu są od razu dostępne w szablonie
- Reaktywność z Vue
Druga sekcja przechowuje dane i logikę. Oprócz znanego już ref() pojawia się w niej funkcja computed(), którą również importujemy z pakietu vue:
1<script setup>
2// LOGIKA - jak działa system
3import { ref, computed } from 'vue'
4
5const systemName = ref('System Podtrzymywania Życia')
6const oxygenLevel = ref(98.5)
7
8const status = computed(() =>
9 oxygenLevel.value > 90 ? 'OPTYMALNY' : 'OSTRZEŻENIE'
10)
11
12const statusClass = computed(() =>
13 oxygenLevel.value > 90 ? 'status-ok' : 'status-warning'
14)
15</script>Funkcja computed() tworzy wartość wyliczaną. Przekazujesz jej funkcję strzałkową, a Vue zapamiętuje wynik i przelicza go sam, gdy zmieni się oxygenLevel. Poziom tlenu pozostaje zwykłym kontenerem ref - status go nie modyfikuje, tylko z niego wynika. W skrypcie wynik odczytasz jako status.value, a w szablonie wystarczy {{ status }}.
3. <style scoped> - Wygląd Panelu
- CSS specyficzny dla modułu
scopedizoluje style - jeden moduł nie psuje drugiego- Ciemne tło, jasne akcenty - standard kosmiczny
Trzecia sekcja opisuje wygląd panelu. Atrybut scoped sprawia, że zapisane tu reguły obowiązują wyłącznie w tym komponencie:
1<style scoped>
2/* WYGLĄD - jak wygląda panel */
3.life-support-panel {
4 background: #0a1628;
5 border: 2px solid #00ff88;
6 border-radius: 8px;
7 padding: 1.5rem;
8 color: #e0e0e0;
9}
10
11.status-ok { color: #00ff88; }
12.status-warning { color: #ffaa00; }
13</style>Vue dodaje elementom komponentu unikalny atrybut w rodzaju data-v-7ba5bd90 i dopisuje go do selektorów, więc klasa .status-ok z innego modułu nie zderzy się z tą. Bez scoped te same reguły działałyby na całej stronie.
Kolejność Sekcji
Vue nie narzuca kolejności bloków. Oficjalny przewodnik stylu zaleca tylko, żeby była spójna w całym projekcie, a <style> stał na końcu - dlatego kreator create-vue stawia <script setup> na górze, a wiele zespołów zaczyna od <template>. W NOVA LAB piszemy w kolejności <template>, <script setup>, <style scoped>: najpierw to, co widzi astronauta, potem okablowanie, na końcu obudowa. Plik może mieć najwyżej jeden <template> i jeden <script setup>, za to bloków <style> dowolnie wiele.
Funkcja pod Przyciskiem
Moduł z samymi odczytami to dopiero połowa systemu. W <script setup> możesz też zadeklarować zwykłą funkcję, a w szablonie podpiąć ją pod przycisk atrybutem @click. Zobacz to na module chłodzenia reaktora:
1<template>
2 <p>Temperatura reaktora: {{ reactorTemp }}°C</p>
3 <p>Stan: {{ coolingStatus }}</p>
4 <button @click="coolDown">Schłodź o 5°C</button>
5</template>
6
7<script setup>
8import { ref, computed } from 'vue'
9
10const reactorTemp = ref(95)
11
12const coolingStatus = computed(() => {
13 if (reactorTemp.value >= 90) return 'KRYTYCZNY'
14 if (reactorTemp.value >= 70) return 'PRZEGRZANIE'
15 return 'W NORMIE'
16})
17
18function coolDown() {
19 reactorTemp.value -= 5
20}
21</script>Kliknięcie uruchamia coolDown, która obniża temperaturę przez .value. Vue zauważa zmianę, computed przelicza stan, a oba akapity odświeżają się same. Funkcja strzałkowa w computed może mieć klamry i kilka instrukcji if - zwracany jest pierwszy pasujący wynik. Obsługę zdarzeń rozbierzemy dokładnie w następnej lekcji.
<script setup> vs stara składnia
Composition API ma dwie formy zapisu. Starsza wymaga eksportu obiektu z funkcją setup(), która na końcu musi zwrócić wszystko, czego używa szablon:
1<!-- PROTOKÓŁ NOWY (zalecany) -->
2<script setup>
3import { ref } from 'vue'
4const pressure = ref(101.3)
5</script>
6
7<!-- STARY PROTOKÓŁ (legacy) -->
8<script>
9import { ref } from 'vue'
10export default {
11 setup() {
12 const pressure = ref(101.3)
13 return { pressure }
14 }
15}
16</script><script setup> to cukier składniowy, który kompilator zamienia właśnie na funkcję setup(), więc zmienne nie wymagają ręcznego return. Starsza forma nie została usunięta i spotkasz ją w starszych projektach. W NOVA LAB używamy wyłącznie nowego protokołu - jest krótszy, szybszy w działaniu i lepiej współpracuje z TypeScriptem - i to polecam Ci od pierwszego pliku.
W edytorze poniżej App.vue wyświetla trzy karty SystemCard. Otwórz plik components/SystemCard.vue i odszukaj w nim wszystkie trzy sekcje. Karta dostaje dane przez defineProps - ten kanał komunikacji poznasz w Stacji Komunikacji.
Zapamiętaj: plik .vue to kompletny moduł stacji - szablon jest panelem, <script setup> okablowaniem, a <style scoped> obudową, która nie przepuszcza stylów do sąsiadów.
Kod do tej lekcji: src/App.vue
1<template>
2 <div class="nova-lab">
3 <h1>Single File Components (SFC)</h1>
4
5 <section class="sfc-demo">
6 <h2>Struktura komponentu .vue</h2>
7 <div class="structure">
8 <div class="part template">
9 <h3><template></h3>
10 <p>HTML struktura komponentu</p>
11 </div>
12 <div class="part script">
13 <h3><script setup></h3>
14 <p>Logika JavaScript/TypeScript</p>
15 </div>
16 <div class="part style">
17 <h3><style scoped></h3>
18 <p>Style CSS tylko dla tego komponentu</p>
19 </div>
20 </div>
21 </section>
22
23 <section class="example">
24 <h2>Przykład: Karta Systemu</h2>
25 <SystemCard
26 name="Generator Tlenu Alpha"
27 status="operational"
28 :power="85"
29 />
30 <SystemCard
31 name="Recykler Wody Beta"
32 status="warning"
33 :power="45"
34 />
35 <SystemCard
36 name="Reaktor Plazmowy"
37 status="critical"
38 :power="12"
39 />
40 </section>
41 </div>
42</template>
43
44<script setup>
45import SystemCard from './components/SystemCard.vue'
46</script>
47
48<style>
49.nova-lab {
50 min-height: 100vh;
51 background: #0a0e27;
52 color: #e0e0e0;
53 padding: 2rem;
54 font-family: system-ui, sans-serif;
55}
56
57h1 {
58 color: #00ff88;
59 text-align: center;
60}
61
62section {
63 background: rgba(26, 30, 55, 0.8);
64 border: 1px solid #00b4d8;
65 border-radius: 12px;
66 padding: 1.5rem;
67 margin: 1.5rem auto;
68 max-width: 800px;
69}
70
71h2 {
72 color: #00b4d8;
73 margin-top: 0;
74}
75
76.structure {
77 display: flex;
78 flex-direction: column;
79 gap: 1rem;
80}
81
82.part {
83 padding: 1rem;
84 border-radius: 8px;
85}
86
87.part h3 {
88 margin: 0 0 0.5rem 0;
89 font-family: monospace;
90}
91
92.part p {
93 margin: 0;
94 font-size: 0.9rem;
95}
96
97.template { background: rgba(0, 255, 136, 0.2); border-left: 4px solid #00ff88; }
98.script { background: rgba(0, 180, 216, 0.2); border-left: 4px solid #00b4d8; }
99.style { background: rgba(255, 170, 0, 0.2); border-left: 4px solid #ffaa00; }
100
101.example {
102 display: flex;
103 flex-direction: column;
104 gap: 1rem;
105}
106</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. Co to jest SFC (Single File Component) w Vue.js?
2. Z jakich trzech sekcji składa się plik .vue?
3. Co robi atrybut 'scoped' w sekcji <style scoped>?
Zadania praktyczne w grze
- Edytor kodu
Uzupełnij Single File Component z sekcją template (nagłówek h1), script setup (zmienna ref) i style scoped.
- Układanie w pionie
Ułóż sekcje pliku .vue w kolejności stosowanej w NOVA LAB:
- Klikanie w kolejności
Ułóż poprawną strukturę sekcji script setup z reaktywną zmienną:
- Edytor kodu
Stwórz komponent panelu systemu z template wyświetlającym dane, script setup z ref() i computed(), oraz style scoped.