INF.03 · JavaScript
Dynamiczne tworzenie i usuwanie elementów DOM
Nowa wiadomość jest nowym elementem
- Kod → próba → wniosek
- DOM i zdarzenia
- Własny projekt
Po tej lekcji: Utworzysz, dołączysz i usuniesz element oraz zbudujesz prototyp czatu.
Samo createElement jeszcze niczego nie wyświetla
document.createElement("p") tworzy obiekt poza widocznym drzewem. Ustaw tekst i klasę, potem dołącz przez appendChild lub append. remove odłącza element. replaceChildren usuwa dotychczasowe dzieci i może wstawić nowe. Twórz przyciski usuwania jako button z type="button" i czytelną nazwą.
Tablica jest danymi, DOM ich widokiem
W koszyku przechowuj dane pozycji i narysuj listę; po usunięciu zmień także dane, inaczej po przerysowaniu pozycja wróci. W prostym czacie, który nie zapisuje historii, wystarczy DOM. Gdy wiele dynamicznych przycisków ma tę samą akcję, można obsłużyć click na rodzicu (delegacja) i znaleźć właściwy przycisk przez closest. Sprawdź, czy znaleziony element rzeczywiście należy do listy.
Losowa odpowiedź i przewijanie
Math.random daje liczbę od 0 włącznie do 1 wyłącznie. Math.floor(Math.random()*odpowiedzi.length) daje poprawny indeks tablicy. Nie wpisuj stałego 8, gdy długość może się zmienić. Po append ustaw scrollTop na scrollHeight, aby pokazać koniec rozmowy. Pusty wpis odrzucaj po trim(). Treść wiadomości pokazuj textContent — także gdy ktoś wpisze znaczniki.
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ę.
createElement → textContent → appendChild
Do body dodaj <ul id="lista"></ul>. Samo utworzenie elementu nie umieszcza go jeszcze w widocznym dokumencie.
Podstawowa forma: const element = document.createElement("nazwa"); rodzic.appendChild(element);
const lista = document.querySelector('#lista');
const pozycja = document.createElement('li');
pozycja.textContent = 'Ocean';
lista.appendChild(pozycja);
const usun = document.createElement('button');
usun.type = 'button';
usun.textContent = 'Usuń Ocean';
usun.addEventListener('click', () => pozycja.remove());
pozycja.appendChild(usun);
- createElement tworzy nowy obiekt li. Ustawiamy jego tekst, dopiero appendChild dołącza go na końcu listy.
- Drugi element to przycisk wewnątrz li. type=button chroni przed przypadkowym wysłaniem formularza.
- Callback pamięta tę konkretną zmienną pozycja. Po kliknięciu remove odłącza właśnie jej element.
- append może przyjąć kilka elementów lub tekstów, appendChild jeden węzeł. replaceChildren usuwa stare dzieci i wstawia nowe — przydaje się przy ponownym rysowaniu całej listy.
Math.random i Math.floor: skąd bierze się odpowiedź czatu?
Najpierw prześledź obliczenie na ustalonej wartości, żeby wynik był przewidywalny. W gotowym czacie ułamek zastąpi Math.random().
Podstawowa forma: Math.floor(Math.random() * tablica.length)
const odpowiedzi = ['Cześć', 'Sprawdzę', 'Dzięki'];
const ulamek = 0.7;
const indeks = Math.floor(ulamek * odpowiedzi.length);
console.log(indeks);
console.log(odpowiedzi[indeks]);
2 Dzięki
- length wynosi 3. Mnożymy 0.7 przez 3, dostajemy około 2.1; Math.floor zaokrągla w dół do 2.
- Odczyt odpowiedzi[2] daje trzeci napis: Dzięki. Indeksy zaczynają się od 0.
- Math.random daje ułamek od 0 włącznie do 1 wyłącznie. Po pomnożeniu i floor możliwe indeksy to 0,1,2. Pusta tablica nie ma poprawnego indeksu, więc musisz wcześniej ją obsłużyć.
- To losowa odpowiedź, nie rozumienie wiadomości. Math.random nie nadaje się do generowania tokenów bezpieczeństwa.
Przewinięcie rozmowy i przywrócenie pola
W czacie po dołączeniu nowego akapitu chcesz zobaczyć koniec rozmowy i od razu wpisać kolejną wiadomość. To trzy różne operacje.
Podstawowa forma: historia.scrollTop = historia.scrollHeight; pole.value = ""; pole.focus();
function przygotujPolePoWyslaniu() {
const historia = document.querySelector('#wiadomosci');
const pole = document.querySelector('#tekst');
historia.scrollTop = historia.scrollHeight;
pole.value = '';
pole.focus();
}
przygotujPolePoWyslaniu();
- scrollHeight to wysokość całej przewijanej treści, scrollTop położenie przewinięcia. Przeglądarka ograniczy podaną wartość do końca dostępnego zakresu.
- value="" czyści pole; nie usuwa już dołączonego akapitu z historii.
- focus przenosi aktywne miejsce wpisywania do pola. To nie wysyła formularza. Pole musi istnieć w HTML; ten fragment wymaga projektu czat.
- Definiujemy osobną funkcję i wywołujemy ją ostatnim wierszem. Lokalne nazwy historia i pole nie kolidują z nazwami w pełnym projekcie. Wywołanie umieść po dołączeniu wiadomości.
Jak czytać pozostałe zapisy w pełnym przykładzie
| Zapis | Znaczenie | Przykład użycia |
|---|---|---|
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" |
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.
Miejsce na listę
<ul id="lista"></ul>
Prześledź kod, potem zmień jedną rzecz
const lista = document.querySelector("#lista");
const pozycja = document.createElement("li");
pozycja.textContent = "Kosmos ";
const usun = document.createElement("button");
usun.type = "button";
usun.textContent = "Usuń Kosmos";
usun.addEventListener("click", () => pozycja.remove());
pozycja.appendChild(usun);
lista.appendChild(pozycja);
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: czat — od formularza do nowej wiadomości
Czat pojawił się w INF.03-02-24.06-SG. To prototyp front-end, nie komunikator sieciowy. Nasz własny wariant ma 9 odpowiedzi, wiadomości i przewijanie.
1. HTML: sekcja historii, podpisane pole i formularz z przyciskiem. Submit daje obsługę kliknięcia i Enter.
2. Pobierz value i trim(); odrzuć same spacje. Funkcja dodajWiadomosc tworzy p, ustawia klasę i textContent, dołącza do historii. Flaga moja wybiera wygląd.
3. Losuj indeks przez Math.floor(Math.random()*length). Te odpowiedzi nie rozumieją treści rozmowy. Po dopisaniu ustaw scrollTop=scrollHeight, wyczyść pole i przywróć fokus.
4. Próby: pusty tekst, polskie litery, znaczniki HTML jako tekst, wiele wiadomości, zmieniona długość tablicy. Aby powstał rzeczywisty komunikator, potrzebne są serwer, konta, autoryzacja rozmów i transport, np. WebSocket; nie załatwia tego sam DOM.
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>
Czat / lokalny prototyp
</title>
<link rel="stylesheet" href="styl.css">
<script src="skrypt.js" defer>
</script>
</head>
<body>
<main>
<h1>
Czat / lokalny prototyp
</h1>
<p>
<small>
Wiadomości zostają tylko w tej karcie. Odpowiedź jest losowana z tablicy — nie pisze do Ciebie inna osoba ani AI. Bez zapisu po odświeżeniu.
</small>
</p>
<section id="wiadomosci" aria-label="Historia rozmowy" tabindex="0">
</section>
<form id="formularz">
<label for="tekst">
Twoja wiadomość (1–240 znaków)
</label>
<input id="tekst" maxlength="240" required autocomplete="off">
<button>
Wyślij
</button>
</form>
<button id="odpowiedz" type="button">
Losuj odpowiedź
</button>
<p id="status" role="status">
</p>
</main>
</body>
</html>
Pełny projekt: skrypt.js
const formularz = document.querySelector('#formularz');
const pole = document.querySelector('#tekst');
const historia = document.querySelector('#wiadomosci');
const status = document.querySelector('#status');
const odpowiedzi = ['Cześć!', 'Sprawdzę to.', 'Dobry pomysł.', 'Jak to działa?', 'Już próbuję.', 'Dzięki za wskazówkę.', 'Zapisuję plik.', 'Zobaczmy wynik.', 'Do zobaczenia!'];
function dodajWiadomosc(autor, tekst, moja = false) {
const akapit = document.createElement('p');
akapit.classList.add('wiadomosc');
if (moja) akapit.classList.add('moja');
akapit.textContent = `${autor}: ${tekst}`;
historia.appendChild(akapit);
historia.scrollTop = historia.scrollHeight;
status.textContent = `Dodano wiadomość. Łącznie: ${historia.children.length}.`;
}
formularz.addEventListener('submit', (zdarzenie) => {
zdarzenie.preventDefault(); // Lokalna demonstracja, bez wysyłania do serwera.
const tekst = pole.value.trim();
if (tekst.length < 1 || tekst.length > 240) {
status.textContent = 'Wpisz od 1 do 240 znaków, nie same spacje.';
return;
}
dodajWiadomosc('Ty', tekst, true);
pole.value = '';
pole.focus();
});
document.querySelector('#odpowiedz').addEventListener('click', () => {
const indeks = Math.floor(Math.random() * odpowiedzi.length);
dodajWiadomosc('Symulator', odpowiedzi[indeks]);
});
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 dwie różne pozycje i usuń tylko pierwszą. Następnie wyślij w czacie tekst <img src=x>: ma być tekstem, nie obrazem.
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ć
- Utworzysz, dołączysz i usuniesz element oraz zbudujesz prototyp czatu.
- 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