od Podstaw
10 godz. 55 min · JavaScript · Full-stack i Programowanie
Piotr PalarzWeb DeveloperJeśli poznałeś już wymienione wyżej technologie, to zapewne zdajesz sobie sprawę z ich ograniczeń. Za pomocą języka HTML tworzymy bowiem strukturę dokumentu, dodajemy treść tekstową, obrazy czy wideo. Aby jednak strona internetowa wyglądała perfekcyjnie, korzystamy z arkuszy stylów CSS, które pozwalają nam opisać wygląd wszystkich elementów HTML, ustawić wielkość tekstu czy dodać tło strony. No właśnie, ale gdzie tutaj interakcyjność?Zapewne już wiesz, że język CSS oferuje tzw. pseudoklasy, które pozwalają nam np. przypisać zmianę koloru elementu po najechaniu na niego kursorem myszy. I to tak naprawdę wszystko, na co możemy zareagować. A co gdybyśmy chcieli po wciśnięciu jakiegoś przycisku wysunąć ukryty panel, sprawdzić poprawność wypełnianego właśnie formularza lub pobrać dane z serwera i wyświetlić je na stronie bez przeładowywania witryny? Dobra wiadomość jest taka, że to wszystko jest możliwe z użyciem języka JavaScript, który “rozumie” każda przeglądarka internetowa.Choć język JavaScript powstał jako język skryptowy na potrzeby stron internetowych, to już dawno temu “wyszedł” z przeglądarek internetowych i może być używany tak naprawdę gdziekolwiek. W kursie, który masz przed sobą, poznasz język JavaScript jako niezależny język programowania, a dopiero później dowiesz się, jak wykorzystywać go do wzbogacania stron internetowych. Dzięki postawieniu grubej linii pomiędzy samym językiem, a Obiektowym Modelem Dokumentu dostępnym w przeglądarkach internetowych, będziesz nie tylko bardzo dobrze rozumiał sam język, ale w przyszłości wykorzystasz go do innych zastosowań.Na początku omówimy ciekawą historię języka JavaScript, a chwilę później rozpoczniemy poznawanie najważniejszych jego konstrukcji. I tak dowiesz się czym są zmienne, jakie typy danych dostępne są w tym języku, czym są liczne operatory, instrukcje warunkowe, pętle, tablice, obiekty i funkcje. Wszystkie te zagadnienia są bardzo podobne w innych językach programowania, dlatego kurs ten jest również świetnym wstępem do programowania w ogóle. Każda z przedstawianych konstrukcji języka jest bardzo dokładnie tłumaczona z myślą osobach początkujących. Nie zmienia to jednak faktu, że nawet osoby znające już podstawy języka JavaScript znajdą tutaj coś dla siebie, gdyż na każdym etapie przedstawiane są również liczne ciekawostki odnośnie danej konstrukcji.Kiedy zrozumiesz już jak działa język JavaScript, przejdziemy do drugiej połowy kursu, gdzie dokładnie omówimy Obiektowy Model Dokumentu, dostępny w przeglądarkach internetowych. Zobaczysz jak przeglądarka tworzy z kodu HTML drzewo dokumentu, jak reprezentowane są poszczególne jego węzły, a także jak język JavaScript potrafi z tym “wewnętrznym światem” współpracować. Dowiesz się jak wyszukiwać na stronie interesujących nas elementów HTML, a także jak tworzyć nowe elementy, przypisywać im treść i wstawiać je na stronę. Popracujemy również z atrybutami elementów, ich klasami i wreszcie ze stylami CSS, abyśmy mogli wpływać dynamicznie na wygląd naszej strony.Zobaczysz również, jak możemy w dowolnym momencie odczytać współrzędne położenia elementu na stronie, a także jego wysokość czy szerokość. Tę wiedzę wykorzystamy później w praktycznym przykładzie.Jeden z rozdziałów kursu poświęcony został zdarzeniom, a więc możliwości reagowania na zachowania użytkownika. Dzięki temu zobaczysz, jak możemy przypisać np. zdarzenie kliknięcia do wybranego elementu, a kiedy zostanie on kliknięty, wykona się przygotowany przez nas kod. Poznasz kilka różnych sposobów na przypisywanie oraz usuwanie zdarzeń, a także dowiesz się czym jest tzw. “bubbling” oraz “capturing” czy jak zablokować domyślną akcję przeglądarki.Przy pisaniu jakiegokolwiek kodu, zawsze pojawiają się błędy, dlatego i tutaj Twoje wątpliwości nie pozostaną bez odpowiedzi. Poznasz wszystkie typu błędów, które mogą się pojawić podczas wykonywania naszego kodu, a także wiele sposobów ich wykrycia i wyeliminowania.W kursie nie brakuje oczywiście praktycznych przykładów, które celowo zostały ułożone tak, aby wykorzystać w nich jak najwięcej zdobytej wcześniej wiedzy. Nie zostaniesz więc sam z poczuciem, że co prawda rozumiesz jak działa dana konstrukcja, ale nie masz pomysłu, kiedy z niej skorzystać. Na początek wykonamy praktyczny projekt losowania liczb z wybranego przedziału tak, aby nie mogły się powtórzyć. Już przy tym projekcie poznasz wiele ciekawych technik i sztuczek.Następnie przejdziemy do nieco bardziej zaawansowanego przykładu i napiszemy skrypt, który pozwoli nam sortować dane w tabeli po wybranych kolumnach, kiedy któraś z nich zostanie kliknięta. Zobaczysz jak sortować dane zarówno malejąco jak i rosnąco, a także jak zmieniać kolejność elementów HTML na stronie.W kolejnym projekcie zajmiemy się walidacją danych wpisywanych do formularza, by ten nie mógł zostać wysłany do serwera tak długo, jak zawiera jakiekolwiek błędy. Zobaczysz tutaj zdarzenia związane z polami formularza, a także sposoby na pobieranie z nich wartości i sprawdzanie czy są one poprawne. Zadbamy także o wrażenia użytkownika i wyświetlimy na stronie stosowne błędy, a także podświetlimy źle uzupełnione pola na czerwono.W przedostatnim projekcie wstawimy na stronę przycisk, który będzie się pojawiał po przewinięciu strony w dół, a znikał po odwrotnej akcji. Co jednak ciekawe, po jego kliknięciu, strona zostanie automatycznie, płynnie przewinięta do samej góry.W ostatnim projekcie stworzymy bardzo efektowny dymek z podpowiedzią, który będzie się pojawiał nad elementem po najechaniu na niego kursorem myszy. Wykorzystamy tutaj mnóstwo ciekawych technik. Dowiesz się również jak swój kod przygotować w taki sposób, abyś mógł go udostępnić innym osobom, by w łatwy sposób skorzystały z przygotowanego Tooltipa na swoich stronach.Kurs kończy się sekcją Tips & Tricks, w której znajdziesz 10 krótkich lekcji. W każdej z nich została omówiona jedna sztuczka. Każda z nich pozwoli Ci jeszcze lepiej zrozumieć język JavaScript, ale przede wszystkim zaoszczędzić czas i kilka linijek często niepotrzebnego kodu.Podsumowując, kurs ten jest nie tylko wprowadzeniem do samego języka JavaScript, ale także do Obiektowego Modelu Dokumentu. Dzięki wyraźnemu rozdzieleniu tych dwóch zagadnień, będziesz mógł w przyszłości wykorzystać język JavaScript także do innych zastosowań, poza przeglądarką internetową.
Kurs ten jest dla wszystkich osób, które znają już podstawy HTML i CSS i chciałyby przejść poziom wyżej i dodać do swoich stron dynamiczności. Żadna wcześniejsza wiedza z zakresu JavaScript czy programowania nie jest wymagana, gdyż wszystkie konstrukcje są starannie tłumaczone. Materiał ten będzie również świetnym odświeżeniem i usystematyzowaniem wiedzy dla osób, które już z tym językiem miały do czynienia. Po przerobieniu tego kursu będziesz gotowy, by poznawać język JavaScript dalej, z kursem JavaScript w Praktyce, który powstał jako dopełnienie tego kursu i porusza nieco bardziej zaawansowane tematy, na które tutaj zabrakło już czasu.
Mam nadzieję, że jesteś ze mną na bieżąco.
Zatem kontynuujemy tworzenie naszej aplikacji do sortowania tabeli po kolumnach. Zakończyliśmy na tym,
że wyświetliłem posortowane tablicę, którą wcześniej tutaj utworzyliśmy, czyli utworzyliśmy tablicę trsArr,
w której mamy pełno tych elementów tr.
Jest to prawdziwa tablica, więc pozwala nam ona używać metody sort i po prostu ją posortowaliśmy według
tego, co w tej tablicy znaleźliśmy, czyli sortowaliśmy tablicę, w której są elementy tr, ale bez problemu
tutaj doszliśmy do ich elementów
poniżej i na ich podstawie posortowaliśmy całe te elementy i teraz mamy taką tablicę i jedyne, co trzeba
zrobić, to wstawić ją tutaj do elementu
tbody. Natomiast nie możemy tutaj odwołać do tbody.appendChild i podać tablicy, więc będziemy musieli
to wszystko zapisać najpierw we fragmencie dokumentu.
Moglibyśmy po tej tablicy oczywiście iterować i upychać po kolei te elementy do tbody, ale w tym
kursie była już lekcja na temat tworzenia fragmentu dokumentu i dlaczego jest to lepsze rozwiązanie.
Dlatego teraz również to zrobimy. Możemy tutaj na górze utworzyć sobie nowy fragment dokumentu, więc
nazwiemy zmienną np. df i document.createDocumentFragment i teraz będziemy chcieli do niego upchnąć
wszystkie te elementy, które tutaj mieliśmy, więc możemy skorzystać z pętli for.
Albo, skoro jest to prawdziwa tablica skorzystać z metody forEach, którą również ci pokazywałem, czyli trsArr
ma taką metodę jak forEach, która na tych pseudotablicach, które są tutaj zwracane np. w tym
miejscu nie jest dostępna, ale na prawdziwych tablicach tak i ta funkcja, którą tutaj podamy, przyjmuje
jeden parametr, czyli każdy kolejny element, więc może to być tr,
możemy go tak nazwać i ona się wykona dla każdego elementu z tej tablicy.
Czyli będziemy mogli każdy z tych elementów wrzucić do documentFragment.
Nie musimy ich tworzyć, bo są to prawdziwe elementy tr, czyli obiekty.
Odwołamy się zatem do documentFragment appendChild i następnie tr, czyli po wykonaniu tej instrukcji będziemy
w tym fragmencie dokumentu, mieć wszystkie te elementy tr. Ponownie, one nie będą kopiowane, to tylko
referencje są tam przekazywane,
żaden problem.
I wiesz już, że taki fragment dokumentu możemy teraz wrzucić na naszą stronę, więc teraz na samym dole
pozostaje odwołać się do table.
Czyli to co tutaj na samej górze zapisałem.
Nie zapisałem tutaj nigdzie tbody, więc możemy teraz sobie to wyszukać w tym miejscu, czyli querySelector
tbody i tutaj appendChild i df, czyli nasz fragment dokumentu.
Zobaczysz, co się stanie na stronie.
Te elementy nie zostaną powielone, bo skoro one już tutaj są, tak jak ci mówiłem, to kiedy drugi raz je próbujemy
wrzucić to przeglądarka jest na tyle cwana, że wie, że należy zamienić je tylko miejscami, czyli kiedy
odświeżę i wcisnę imię, to
pojawił nam się jakiś błąd.
Przejdźmy do konsoli, zobaczymy,
trsArray is not defined w linijce czterdziestej czwartej. Zerknijmy.
Oczywiście ta zmienna nazywała się trsArr i jeszcze raz odświeżamy.
Klikam imię i zostało to wszystko posortowane, ale jak widzisz w kolejności odwrotnej, zaraz jeszcze
sobie z tym poradzimy, ale działa.
Jeżeli wciśniemy mu nazwisko to sortujemy po nazwisku Jeżeli wiek, to po wieku.
Niesamowite, bo wszystko działa jak należy.
Natomiast teraz będziemy chcieli sortować w odwrotnej kolejności, aby to tutaj to działało odwrotnie.
To jedyne, co musimy zmienić w tej funkcji sortującej, te zwracane wartości.
I teraz to będzie działać poprawnie.
Jak widzisz, to nie jest tak, że wartości gdzieś, tylko tutaj są sortowane, a tutaj się nie zmieniają, bo
to cały wiersz jest zamieniany.
I jak widzisz, działa wszystko jak należy.
Teraz chciałbym ci jeszcze pokazać, że ja sobie tutaj w CSS wcześniej zdefiniowałem odpowiednie klasy.
Czyli jeżeli do takiego th, tutaj kliknę dwukrotnie wcisnę tab, dodamy klasę np. asc, bo tak ją zdefiniowałem
to tutaj pojawi się taka oto strzałeczka.
A jeżeli zamienię ją na dsc, descending, czyli malejącego.
Musi być e, to pojawi się taka strzałeczka.
I chciałbym teraz właśnie po kliknięciu, kiedy raz klikniemy, aby to było posortowane w ten sposób, aby
taka strzałka się pojawiła.
A kiedy kliknę drugi raz, aby ta strzałka się odwróciła, czyli klasa się zmieniła właśnie na asc i aby
to zostało posortowane w odwrotnej kolejności.
No i możemy to również bez problemu zrobić.
Zauważ, że na początku te wszystkie th, nie mają żadnej klasy, więc będziemy chcieli,
kiedy nie ma żadnej kasy, aby było to sortowanie w taki sposób od A do Z.
I teraz jak będziemy to mogli zrobić.
Otóż możemy tutaj się posłużyć jeszcze jedną nową zmienną, którą nazwiemy order.
Jak kolejność i odwołamy się do target, który tutaj zapisaliśmy.
Wiemy, że target to będzie jeden z tych elementów th, które się tutaj znajdują i możemy sprawdzić czy
on zawiera pewną klasę, która nas interesuje, więc pamiętasz, że mogło to być classList.contains.
Jest taka metoda, ale tutaj prościej możemy się odwołać do, po prostu, do className.
Jeżeli className będzie równe pusty ciąg znaków.
Tak jest w tym przypadku, bo nie ma tutaj żadnej klasy na początku może to nawet pogrupujmy, tak żeby
to lepiej wyglądało.
Jeżeli className będzie pusty albo będzie ustawiony na desc, czyli descending, co za chwilę zobaczysz, więc
sprawdźmy target znowu className równa się desc.
Pamiętaj, że gdybyśmy tutaj przypisali więcej klas, to mielibyśmy problem.
Dlatego, że className, wtedy zwróci je wszystkie.
Wtedy lepiej skorzystać z klasy listContains.
Ale teraz mówimy, jeżeli target.className, to jest pusty ciąg znaków, czyli tak jak tutaj nie mamy klasy.
Czyli tu już mamy true, albo nie jest pusty, ale ma wartości desc, to wtedy chcemy, aby order odwrócić czyli
przypisać tutaj asc, a w przeciwnym wypadku desc. Zaraz zobaczysz, dlaczego ma to sens.
Teraz przejdźmy poniżej i zróbmy console.log order.
No i zobaczymy jak to wygląda.
Przejdźmy do konsoli.
Po kliknięciu na element, order to będzie asc.
Czyli jeżeli w ogóle nie był przypisany, to chcemy go ustawić na ascending.
I taką klasę będziemy chcieli sobie tutaj dodać. do tego elementu.
Możemy to zrobić gdzieś tutaj, nawet na samym dole.
Odwołajmy się do target.className równa się order, czyli to, co przed chwilą pokazałem.
Zobaczmy od razu, jak na to nasza aplikacja zareaguje.
Jak widzisz, dodałem klasę właśnie asc, o ci której mówiłem.
I taka strzałeczka dzięki temu się pojawiła, bo jest zdefiniowana w kodzie CSS.
I teraz kiedy ponownie klikniemy na ten element. Zauważ, co się stanie.
Sprawdzimy czy className jest puste, nie jest lub ma wartość desc. Nie ma wartości desc.
Czyli chcemy tutaj przypisać desc, bo jeżeli byłoby puste lub miałoby wartość desc to do order zapisujemy
asc,
w przeciwnym wypadku zapisujemy desc i o to nam chodziło.
Czyli teraz jeślibym sobie tutaj znowu zrobił console.log,
zobaczmy. To mamy
asc, zobaczymy.
Jeśli kliknę jeszcze raz to jest desc, jeśli jeszcze raz to asc, czyli po prostu wymieniamy.
I podobnie będzie to działać tutaj.
O to właśnie chodziło.
Tylko, jeżeli sobie kliknę teraz na taki oto element, to chciałbym, aby ta strzałeczka zniknęła z tego
elementu, co za moment uczynimy.
Teraz jednak jest rzecz ważniejsza, bo owszem tutaj się to wszystko zmienia, ale sortowanie już nie.
Czyli to, co mamy tutaj pod spodem, musimy również uzależnić od tego, co mamy w zmiennej order, więc przejdźmy
tutaj.
I zrobimy rzecz prostą, tutaj również sprawdzimy, jeżeli order równa się asc, to chcemy zwrócić
minus 1.
W przeciwnym wypadku chcemy zwrócić 1.
No i tutaj zrobimy rzecz podobną, tylko że na odwrót.
Tutaj będzie minus 1.
No i teraz to będzie działać.
Czyli jeżeli na początku będziemy mieli order asc, to zwrócimy minus 1. Natomiast jeżeli zamieni on się
na desc, to zwrócimy 1, czyli to sortowanie się po prostu odwróci, co już wcześniej pokazałem.
Zobaczmy, jak to działa.
Adrian, klikam jeszcze raz i w drugą stronę też sortowane, super, wszystko działa, jak należy.
Podobnie będzie tutaj.
Natomiast, kiedy klikam tutaj, chciałbym, aby tutaj strzałeczka zniknęła, więc ostatnia rzecz, którą musimy
zrobić to z wszystkich tych elementów usunąć
klasę CSS.
No bo jeżeli klikniemy tutaj nie wiemy, gdzie ta klasa wcześniej była, czyli ze wszystkich tych elementów
możemy klasę usunąć.
No i w tym celu stworzymy funkcję pomocniczą.
Ja od razu ją wkleję.
Jest to funkcja, którą nazwałem clearClassName.
Podajemy jej tutaj nodeList, czyli znowu taki element tablicopodobny, wszystkie te ths'y.
Będziemy chcieli po nich przeiterować i każdemu z nich usunąć klasę, czyli zresetować na pusty ciąg
znaków.
I teraz nam to zadziała.
Będziemy chcieli to zrobić w tym miejscu.
Tutaj będziemy je resetować.
A na dole je przypisujemy, OK.
Czyli tu możemy napisać clearClassName i przekazać tutaj elementy th, które mieliśmy wcześniej, czyli
ths.
W ten sposób, za każdym razem kiedy gdzieś klikniemy, funkcja sortBy się wykonuje, to usuniemy z wszystkich
elementów ths klasę i
jeżeli je usuniemy to te strzałeczki poznikają.
Natomiast, na samym dole tej funkcji, do elementu który właśnie kliknęliśmy, przypisujemy klasę i stąd ta
strzałka się tutaj pojawia.
Jeżeli tutaj kliknę, znowu ze wszystkich, czyli z tego z tego i z tego usuniemy klasę, tutaj ta strzałka przez to
zniknie.
A na dole dodajemy i pojawi się ona tutaj.
Jak widzisz, wszystko działa fantastycznie i tak naprawdę zakończyliśmy teraz tworzenie naszej aplikacji.
Był to dosyć skomplikowany projekt, ale mam nadzieję, że dobrze go zrozumiałeś.
Możesz jeszcze raz obejrzeć to i poprzednie wideo.
Jestem przekonany, że wszystko zrozumiesz, bo starałem się wszystko najdokładniej, jak potrafię wytłumaczyć.
Oczywiście do podejścia sortowania takiej tabeli można podejść jeszcze inaczej.
Można to zrobić inny sposób, natomiast to jest sposób, jaki mi przyszedł do głowy. Wydaje mi się, że nie jest najgorszy.
Sortowanie tabeli po kolumnach cz. 2 - start · 1 min
(function() {
var table = document.querySelector("#myTable"),
ths = table.querySelectorAll("thead th"),
trs = table.querySelectorAll("tbody tr");
function makeArray(nodeList) {
var arr = [];
for(var i = 0; i < nodeList.length; i++) {
arr.push(nodeList[i]);
}
return arr;
}
function sortBy(e) {
var target = e.target,
thsArr = makeArray(ths),
trsArr = makeArray(trs),
index = thsArr.indexOf(target);
trsArr.sort(function(a, b) {
var tdA = a.children[index].textContent,
tdB = b.children[index].textContent;
if(tdA < tdB) {
return 1;
} else if(tdA > tdB) {
return -1;
} else {
return 0;
}
console.log(trsArr);
});
}
for(var i = 0; i < ths.length; i++) {
ths[i].onclick = sortBy;
}
})();Sortowanie tabeli po kolumnach cz. 2 · 1 min
(function() {
var table = document.querySelector("#myTable"),
ths = table.querySelectorAll("thead th"),
trs = table.querySelectorAll("tbody tr");
function makeArray(nodeList) {
var arr = [];
for(var i = 0; i < nodeList.length; i++) {
arr.push(nodeList[i]);
}
return arr;
}
function clearClassName(nodeList) {
for(var i = 0; i < nodeList.length; i++) {
nodeList[i].className = "";
}
}
function sortBy(e) {
var target = e.target,
thsArr = makeArray(ths),
trsArr = makeArray(trs),
index = thsArr.indexOf(target),
df = document.createDocumentFragment(),
order = (target.className === "" || target.className === "desc") ? "asc" : "desc";
clearClassName(ths);
trsArr.sort(function(a, b) {
var tdA = a.children[index].textContent,
tdB = b.children[index].textContent;
if(tdA < tdB) {
return order === "asc" ? -1 : 1;
} else if(tdA > tdB) {
return order === "asc" ? 1 : -1;
} else {
return 0;
}
});
trsArr.forEach(function(tr) {
df.appendChild(tr);
});
target.className = order;
table.querySelector("tbody").appendChild(df);
}
for(var i = 0; i < ths.length; i++) {
ths[i].onclick = sortBy;
}
})();