INF.03 · JavaScript
Obsługa zdarzeń — myszy i klawiatury
Kliknięcie, Enter i wpisywanie to różne zdarzenia
- Kod → próba → wniosek
- DOM i zdarzenia
- Własny projekt
Po tej lekcji: Podepniesz zdarzenie do elementu i obsłużysz formularz także klawiaturą.
Zarejestruj reakcję, nie uruchamiaj jej od razu
element.addEventListener("click", funkcja) przekazuje funkcję do późniejszego wykonania. funkcja() wywołałaby ją teraz. Obiekt zdarzenia zawiera m.in. target i key. input reaguje w trakcie edycji, change zwykle po zatwierdzeniu wartości. keydown to naciśnięcie klawisza. Używaj zwykłego button zamiast klikalnego div: dostajesz fokus i klawiaturę.
Formularz ma zdarzenie submit
Obsługa submit działa przy przycisku oraz Enter w odpowiednim polu. preventDefault zatrzymuje domyślne wysłanie, np. w lokalnym kalkulatorze. Nie blokuj wszystkich Enter na document. Przyciski pomocnicze w formularzu powinny mieć type="button", bo domyślny button może wysłać formularz. hover nie wystarcza na telefonie; istotna akcja potrzebuje kliknięcia i widocznego fokusu.
Prześledź jedno zdarzenie
W modelu najpierw kliknij przycisk, potem wpisz imię i naciśnij Enter. To dwie drogi do tego samego submit. Z kolei suwak wywołuje input. W planszy każdy ruch jest click, a funkcja sprawdza stan przed zmianą. Zmiana wyglądu przycisku nie zastępuje reguły blokującej ponowny ruch.
Najpierw krótki przykład, potem cały projekt
Każdy krótki przykład uruchamiaj osobno: w oddzielnym pliku skrypt.js lub na nowej pustej stronie. Nie doklejaj kilku przykładów z tym samym const do jednego pliku, bo ponowna deklaracja tej samej nazwy jest błędem. Przykłady konsolowe pokażą wynik w F12 → Console. Przy przykładach DOM najpierw utwórz wskazane elementy HTML i podłącz skrypt z defer. Fragment wymagający gotowego projektu jest tak oznaczony — wykonuj go w jego kontekście, nie jako pustą stronę.
addEventListener: reakcja czeka na zdarzenie
W HTML potrzebujesz <button id="pokaz">Pokaż</button><p id="wynik"></p>. Skrypt podłącz z defer. Zarejestruj funkcję, zamiast wywoływać ją podczas ładowania.
Podstawowa forma: element.addEventListener("nazwaZdarzenia", funkcja);
const przycisk = document.querySelector('#pokaz');
function pokaz(zdarzenie) {
document.querySelector('#wynik').textContent = 'Kliknięto';
console.log(zdarzenie.type);
}
przycisk.addEventListener('click', pokaz);
- Pierwszy argument click jest nazwą zdarzenia; drugi to funkcja bez nawiasów wywołania. pokaz() wykonałoby się teraz, a nie po kliknięciu.
- Przeglądarka przekazuje do pokaz obiekt zdarzenia. type daje nazwę, target element będący źródłem zdarzenia, currentTarget element z tym listenerem.
- Wciśnięcie Enter lub spacji na przycisku również uruchamia kliknięcie. Dlatego button jest lepszy od div udającego przycisk.
input i keydown: co użytkownik właśnie zrobił?
Do body dodaj <input id="imie"><p id="licznik"></p>. input reaguje na zmianę wartości, także wklejenie tekstu. keydown reaguje na naciśnięcie klawisza.
Podstawowa forma: pole.addEventListener("input", callback); klawisz odczytasz z zdarzenie.key
const pole = document.querySelector('#imie');
pole.addEventListener('input', () => {
document.querySelector('#licznik').textContent = pole.value.length;
});
pole.addEventListener('keydown', (zdarzenie) => {
if (zdarzenie.key === 'Escape') {
pole.value = '';
document.querySelector('#licznik').textContent = '0';
}
});
- pole.value daje bieżący tekst. length to długość napisu liczona w jednostkach UTF-16, więc nie dla każdego emoji oznacza liczbę widocznych znaków.
- W keydown porównujemy key z napisem Escape. Dla innych klawiszy blok if się nie wykona.
- Ustawienie value w kodzie samo nie wywołuje input, dlatego po Escape aktualizujemy także licznik. Do wysyłania formularza służy submit, nie globalne przechwycenie Enter.
Plansza: fill, forEach, disabled i fokus
Zanim czytasz pełną grę, zobacz prosty stan planszy. Pusty napis oznacza wolne pole; nie jest obrazkiem pustego przycisku.
Podstawowa forma: Array(9).fill("") tworzy dziewięć pustych pól; tablica.forEach((wartosc, indeks) => {...}) odwiedza je po kolei
const pola = Array(9).fill('');
pola[0] = 'O';
pola.forEach((znak, indeks) => {
if (indeks < 2) console.log(indeks, znak || 'puste');
});
console.log(pola.length);
0 O 1 puste 9
- Array(9) tworzy tablicę o długości9, a fill wypełnia miejsca pustym napisem. Na indeks0 wpisujemy O.
- forEach przekazuje do callbacku znak i indeks. Nie są to globalne zmienne ani słowa kluczowe — sami wybraliśmy ich nazwy.
-
znak || "puste"wybiera drugi napis, gdy znak jest pusty. To nie to samo co ??, które reaguje tylko na null/undefined. - W pełnej grze disabled=true blokuje przycisk zajętego pola. focus() przenosi fokus klawiatury na kolejny dostępny przycisk; nie wykonuje za niego ruchu.
Jak czytać pozostałe zapisy w pełnym przykładzie
| Zapis | Znaczenie | Przykład użycia |
|---|---|---|
some / every | some pyta, czy choć jeden element spełnia warunek, every czy wszystkie. Dla pustej tablicy some=false, every=true. | pola.every(znak => znak !== "") |
([a,b,c]) => ... | Parametr callbacku zostaje rozpakowany z jednej tablicy do trzech nazw. To nie trzy osobne argumenty przekazane przez some. | linie.some(([a,b,c]) => pola[a] === pola[b]) |
warunek ? A : B | Wyrażenie warunkowe zwraca A przy prawdzie, B przy fałszu. Można go użyć po prawej stronie przypisania. | gracz = gracz === "O" ? "X" : "O"; |
Array(9).fill("") | Tworzy dziewięć pozycji i wypełnia je pustym napisem. fill z obiektem współdzieliłoby ten sam obiekt; tutaj używamy napisów. | let pola = Array(9).fill(""); |
replaceChildren / append | Pierwsza metoda zastępuje wszystkie dzieci elementu, druga dopisuje podane węzły/teksty na końcu. | karta.append(tytul, data, lista); |
addEventListener / preventDefault | Pierwsza metoda rejestruje funkcję na zdarzenie, druga zatrzymuje jego domyślną akcję (np.wysłanieformularza), nie usuwa innych listenerów. | form.addEventListener("submit", e => e.preventDefault()); |
&& / || / ?? | && wymaga prawdy po obu stronach, || wybiera także dla pustego napisu/0, ?? tylko dla null/undefined. Te operatory mogą zwracać operandy, nie wyłącznie bool. | znak || "puste" |
=== i !== | Porównanie bez konwersji typów. Przypisanie ma pojedyncze =. | 7 === "7" // false |
Sprawdź w działaniu
Sprawdź mechanizm na działającym przykładzie
Zmień dane, przewidź wynik i wykonaj próbę. To działający JavaScript tego modelu, nie interpreter dowolnego wklejonego kodu.
HTML w body pliku index.html
<form id="formularz"><label for="imie">Imię</label>
<input id="imie"><button>Przywitaj</button></form>
<p id="wynik"></p>
Prześledź kod, potem zmień jedną rzecz
const formularz = document.querySelector("#formularz");
formularz.addEventListener("submit", (zdarzenie) => {
zdarzenie.preventDefault();
const imie = document.querySelector("#imie").value.trim();
document.querySelector("#wynik").textContent = imie ? `Cześć, ${imie}!` : "Wpisz imię.";
});
Odtwórz przykład u siebie
Zapisz pokazany JavaScript w skrypt.js, a HTML w body zwykłego dokumentu z <!doctype html>, lang="pl", meta charset="UTF-8" i tytułem. W head podłącz <script src="skrypt.js" defer></script>. Przykłady z samym console.log możesz wykonać też w konsoli własnej pustej strony. Nie wklejaj nieznanych skryptów do konsoli zalogowanych serwisów. F12 → Console: sprawdź błędy; Sources: ustaw breakpoint, obejrzyj zmienne i przejdź krokowo.
Projekt: kółko i krzyżyk — widok wynika ze stanu
INF.03-07-26.06-SG wymagał naprzemiennych ruchów, aktualizacji widoku i zablokowania zajętego pola. Nasz wariant dodatkowo sprawdza zwycięstwo i remis; ma własny układ przycisków.
1. Tablica pola ma 9 pustych napisów. gracz przechowuje O lub X, koniec blokuje dalszą grę. rysuj tworzy przyciski z nazwą pola i znakiem; disabled wynika ze stanu.
2. Kliknięcie przekazuje indeks do wykonajRuch. Najpierw sprawdza blokadę, potem zapisuje znak. To ważne: sam kolor pola nie zabezpiecza przed zmianą.
3. Osiem trójek indeksów opisuje wiersze, kolumny i przekątne. some szuka zwycięskiej trójki; every sprawdza zapełnienie. Jeśli nikt nie wygrał i zostały miejsca, zmień gracza i przerysuj.
4. Zagraj zwycięski wiersz, przekątną, remis; kliknij zajęte pole i zresetuj grę. Sprawdź także Tab i Enter. Nie używamy zdjęć ani treści z załączników egzaminu.
Sprawdź w działaniu
Uruchom gotowy projekt i porównaj z kodem
W podglądzie działa gotowy kod. Komplet HTML/CSS/JS pobierzesz w paczce na końcu. Podgląd jest izolowany od konta BitEdu.
Pełny projekt: index.html
<!doctype html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>
Kółko i krzyżyk / stan gry
</title>
<link rel="stylesheet" href="styl.css">
<script src="skrypt.js" defer>
</script>
</head>
<body>
<main>
<h1>
Kółko i krzyżyk / stan gry
</h1>
<p>
Dwie osoby grają przy jednym ekranie. Zajętego pola nie można zmienić. Własne rozszerzenie: wykrywanie wygranej i remisu.
</p>
<div id="plansza" class="plansza" aria-label="Plansza trzy na trzy">
</div>
<p id="status" role="status">
</p>
<button id="reset" type="button">
Nowa gra
</button>
</main>
</body>
</html>
Pełny projekt: skrypt.js
const plansza = document.querySelector('#plansza');
const status = document.querySelector('#status');
const linie = [[0,1,2], [3,4,5], [6,7,8], [0,3,6], [1,4,7], [2,5,8], [0,4,8], [2,4,6]];
let pola = Array(9).fill('');
let gracz = 'O';
let koniec = false;
function rysuj() {
plansza.replaceChildren();
pola.forEach((znak, indeks) => {
const przycisk = document.createElement('button');
przycisk.type = 'button';
przycisk.textContent = znak || '·';
przycisk.setAttribute('aria-label', `Pole ${indeks + 1}: ${znak || 'puste'}`);
przycisk.disabled = koniec || znak !== '';
przycisk.addEventListener('click', () => wykonajRuch(indeks));
plansza.appendChild(przycisk);
});
}
function wykonajRuch(indeks) {
if (koniec || pola[indeks] !== '') return;
pola[indeks] = gracz;
const wygrana = linie.some(([a,b,c]) => pola[a] !== '' && pola[a] === pola[b] && pola[b] === pola[c]);
if (wygrana) {
koniec = true;
status.textContent = `Wygrywa ${gracz}.`;
} else if (pola.every(znak => znak !== '')) {
koniec = true;
status.textContent = 'Remis.';
} else {
gracz = gracz === 'O' ? 'X' : 'O';
status.textContent = `Ruch: ${gracz}.`;
}
rysuj();
const nastepne = plansza.querySelector('button:not(:disabled)');
if (nastepne) nastepne.focus();
}
document.querySelector('#reset').addEventListener('click', () => {
pola = Array(9).fill(''); gracz = 'O'; koniec = false;
status.textContent = 'Ruch: O.'; rysuj();
});
status.textContent = 'Ruch: O.';
rysuj();
Wygląd też jest częścią paczki
Folder projektu zawiera również pełny styl.css, a karty — dane.json. Rozpakuj ZIP JS / WARSZTAT ze „Źródeł i materiałów”. Otwórz index.html; dla dodatkowego odczytu JSON uruchom lokalny serwer opisany w START.txt. Podgląd nie zastępuje wykonania własnej wersji.
Ćwiczenie z pomocą · samodzielna praca
Twoja próba
Dodaj licznik znaków reagujący na input. Wyślij formularz myszą i Enter. Wynik ma być taki sam.
Zapisz: dane → przewidywany wynik → wynik próby → wyjaśnienie.
? Potrzebujesz pomocy? Rozwiązuj krok po kroku.
Krok 1 — pokaż podpowiedź
Zacznij od działającego przykładu i przewidź wynik bez uruchamiania.
Krok 2 — pokaż podpowiedź
Zmień jedną instrukcję lub jedną wartość. Obejrzyj Console i stan DOM.
Krok 3 — pokaż podpowiedź
Dodaj przypadek pusty albo graniczny. Jeśli wynik jest inny, ustaw breakpoint.
Otwórz tylko tyle podpowiedzi, ile potrzebujesz. Po każdym kroku wróć do zadania i sprawdź wynik.
Podsumowanie
Co warto zapamiętać
- Podepniesz zdarzenie do elementu i obsłużysz formularz także klawiaturą.
- Umiesz wskazać przyczynę wyniku w kodzie i sprawdzić przypadek graniczny.
- Quiz i dodatkowe zadania są w biurku; kod ocenia nauczyciel.
Dalej na swoim koncie
Rozgrzewki, quiz i zadania są w biurku ucznia.
Teoria jest otwarta dla wszystkich. Żeby rozwiązywać zadania, zapisywać szkice i widzieć swój postęp, zaloguj się.
Zaloguj się →Źródła i dalsza nauka
- JS / WARSZTAT.zip — 4 pełne projekty i START.txt
- CKE — informator INF.03 (wymagania INF.03.5)
- CKE — arkusz INF.03-02-24.06-SG, czat (kopia szkoły)
- CKE — arkusz INF.03-07-26.06-SG, plansza (kopia archiwalna)
- CKE — arkusz INF.03-06-26.06-SG, dane i DOM (kopia archiwalna)
- MDN — przewodnik JavaScript
- MDN — const
- MDN — fetch
- Dokumentacja składni omawianego języka