Kurs Vue.js · Moduł 1: Vue i Vite

Single File Components - Moduły Systemu

5 min czytania
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
  • scoped izoluje 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>&lt;template&gt;</h3>
10          <p>HTML struktura komponentu</p>
11        </div>
12        <div class="part script">
13          <h3>&lt;script setup&gt;</h3>
14          <p>Logika JavaScript/TypeScript</p>
15        </div>
16        <div class="part style">
17          <h3>&lt;style scoped&gt;</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. 1. Co to jest SFC (Single File Component) w Vue.js?

  2. 2. Z jakich trzech sekcji składa się plik .vue?

  3. 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.

Przydatne artykuły