JavaScript – wstęp do programowania
Struktura strony
W projekcie każdej strony internetowej można wyróżnić trzy główne aspekty (warstwy): treść (content), wygląd (styl) oraz sposób zachowania (dynamika). Jak już była o tym mowa – treść opisujemy przy pomocy języka HTML a wygląd za pomocą CSS. Za aspekt dynamiczny odpowiada głównie JavaScript.
Mówiąc o dynamicznych zmianach i JavaScrpt trzeba pamiętać, żemowa jest tu o zmianach (ruchu) w aktualnie oglądanej stronie (po jej wczytaniu). Nie należy tego utożsamiać z podziałem stron na statyczne i dynamicze.
Strony statyczne to takie, które nie są tworzone przez programy w trakcie wczytywania, ale ich treść została wcześniej w pełni przygotowana i zapisana w plikach HTML i CSS. Takie strony także mogą siż zmieniać – na przykład przy zmianie wielkości ekranu. Strony dynamiczne to takie których zachowanie lub wygląd definiuje program. Tu sprawa nieco się komplikuje, bo program może być wykonywany przez przeglądarkę internetową (frontend) lub serwer www (backend). W nieniejszym rozdziale mowa właśnie o tym, co dzieje się po stronie frontendu -gdzie używany jest JavaScript. Czy stronę zawierającą bogatą aplikację w JavaScript nazwać statyczną czy dynamiczną? To nie ma większego znaczenia (często przyjmuje się po prostu, że dynamiczne = z treścią pamiętaną w bazie danych).
Nawigacja
Zmiany w naszej przeglądarce najczęściej polegają na nawigacji – czyli przechodzeniu od strony do strony. Sterujemy tym używając przede wszystkim linków (url, znacznik a) oraz formularzy (znacznik form i input).
Renderowanie
Renderowanie – tworzenie wyglądu na podstawie opisu. Zazwyczaj pojęcie to odnosi się do tworzenia wyglądu przez przeglądarkę internetową.
Renderowanie w przeglądarce zaczyna się po pobraniu kodu HTML i CSS. W narzędziach dla webmasterów firmy Google
(https://www.google.com/webmasters/tools/) można znaleźć „zobacz jako Google”, które pozwala sprawdzić, czy nasza strona jest tak samo widziana przez użytkownika jak i przez przeglądarkę. Jest tam opcja „renderuj”. Szczegółowy opis tego procesu (po angielsku): https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/.
Drzewo DOM
Renderowanie w przeglądarce rozpoczyna się od zbudowania drzewa DOM na podstawie znaczników HTML. Drzewo – bo znaczniki są zagnieżdżane (tworzą strukturę drzewa). Zobaczmy jak to wygląda dla prostej strony
(źródło):
<html>
<head>
<meta charset="utf-8">
<link href="style.css" rel="stylesheet">
<title>Critical Path</title>
</head>
<body>
<p>Hello <span>web performance</span>
students!</p>
<div><img src="awesome-photo.jpg"></div>
</body>
</html>
Obiekty
Każdy węzeł (node) tego drzewa (zaznaczone na żółto) jest obiektem. Czyli nie tylko jest to prosta wartość (jak liczba), ale zawiera własności (na przykład identyfikator). Na popielato zaznaczono jedną z własności - wyświetlaną treść.
Abstrakcyjne pojęcie obiektu jest obok zmiennej jednym z najważniejszych w informatyce. Zmienna to fragment pamięci komputera oznaczony nazwą. Obiektem jest struktura, która ma swoje własności (które także mogą być obiektami) i metody zmian tych własności (więcej: Programowanie : Uczymy_się myśleć abstrakcyjnie).
Ważne jest aby rozróżniać obiekt i klasę obiektów. Na przykład mamy obiekt Jana Kowalskiego klasy Student, która jest podklasą Ludzi. W przypadku drzewa DOM mamy klasy obiektów zdefiniowane przez znaczniki (np. div). Drzewo DOM jest obiektową strukturą strony internetowej (zob: https://pl.wikipedia.org/wiki/Obiektowy_model_dokumentu).
Uwaga terminologiczna. To nie są klasy definiowane przez atrybut / własność znaczników class. Nazwa klasy znaczników (własność class) uważana jest na poziomie drzewa DOM za własność obiektów (węzłów drzewa). Przez analogię można to porównać do nazwisk ludzi. Nazwisko to własność każdego człowieka, ale pozwala też wyróżnić grupę ludzi o takim samym nazwisku. Gdyby w języku polskim zamiast słowo "nazwisko" funkcjonowało słowo "klasa", to milibyśmy podobny kłopot z wyjaśnieniem pojęcia "klasy ludzi". Gdy mowa o DOM - można po prostu na chwilę zapomnieć o słowie "class" i traktować klasę jako rodzaj znacznika.
Program w JavaScript może odczytywać i zmieniać własności drzewa DOM (choć sam język nie jest w pełni obiektowy – bo nie pozwala tworzyć struktur nowych klas obiektów).
Zdarzenia
Zdazrenia obsługujemy skryptami napisanymi w JavaScript. Spróbujmy na początek wykonać prosty przykład. Uruchamiamy: http://jsbin.com/folowenasa/edit?html,css,js,console,output
Wpiszmy w treść strony jakiś tekst – na przykład „Kliknij tutaj”.
Do znacznika <body> dodajmy własność „onclick” i nadajmy jej wartość „test();”. Będzie to znaczyć, że po kliknięciu na stronie wykona się procedura „test”.
<body onclick="test();">kliknij tutaj</body>
Procedura musi zostać napisana – żeby się wykonała:
function test() {
alert('!');
}
Poniższa tabelka zawiera opis wszystkich symboli użytych w tym programiku:
symbol | Znaczenie | oznaczanie |
---|---|---|
body | Część języka HTML w którym opisujemy strony internetowe. W tym wypadku znacznik używany do ograniczenia całej strony. | Oznacza wnętrze (treść) strony. |
<> | Dwa symbole określające początek i koniec znacznika. | Miejsce w tekście gdzie zaczyna się i kończy znacznik. |
/ | Zmienia znaczenie znacznika (koniec oznaczanego obszaru) – o ile występuje natychmiast po znaku < | |
onclick | Własność dodawana do znacznika. Po znaku = nadaje się tej własności wartość. | Co się stanie, gdy klikniemy na wskazywane przez znacznik miejsce. |
function | Symbol używany do zdefiniowania fragmentu kodu (programu) nazywanego funkcją. | Definicję jakiejś funkcji. |
test | Symbol zdefiniowany przez nas – konkretnej funkcji. | Definicję konkretnej funkcji test. |
alert | Wyświetlenie komunikatu | Funkcję zdefiniowaną (wbudowaną) w przeglądarce. |
{ | Znaki używane dla interpretera (przeglądarki internetowej) – aby mógł zrozumieć znaczenie tekstu | Początek procedury |
} | Koniec procedury | |
; | Koniec fragmentu procedury zawierającą instrukcję (zob niżej). | |
" | Cudzysłów oznaczający początek i koniec napisu. | |
= | Znak równości (własność ma określoną wartość) | |
( | Początek miejsca na parametry funkcji | |
) | Koniec miejsca na parametry funkcji |
Więcej informacji: http://www.w3schools.com/html/html_intro.asp (można wybrać polskie tłumaczenie – jest dość porządne) .http://pdf.helion.pl/e14te3/e14te3.pdf (rozdział 3.8 i dalej).
Jak widzimy - uruchomienie programu następuje wskutek jakiegoś zdarzenia. Najważniejszym zdarzeniem w przeglądarce jest załadowanie strony. Proces ten przebiega współbieżnie. Przeglądarka ściąga dane z serwera. Po ściągnięciu CSS i HTML rozpoczyna budowę drzewa DOM i renderowanie strony (dlatego mówi się, że CSS i HTML blokują renderowanie - proces rozpoczyna się po skompletowaniu CSS i HTML).
Po załadowaniu i zrenderowaniu strony jest ona wyświetlana – choć mogą być ściągane kolejne jej elementy (jak obrazki i skrypty JavaScript). Gdy przeglądarka uzna, że ma już komplet – wywołuje zdarzenie onload – na rzecz obiektu document (znacznik body). Zaleca się, aby skrypty które nie zawierają obsługi tego zdarzenia umieszczać nie w nagłówku, ale na końcu strony (wtedy onload zachodzi wcześniej - nawet gdy nie skończy się proces pobierania skryptów).
Poza onload najczęściej wykorzystuje się zdarzenie onclick wywoływane na rzecz obiektów z drzewa DOM (zobacz pełną listę
zdarzeń).
Przejdźmy do jednego z serwisów pozwalających na testowanie programów w JavaScript strony(http://codepen.io/pen/ lub https://jsfiddle.net/ lub http://jsbin.com/) i przeanalizujmy prosty przykład.
Przykład 1:
<html>
<head>
<meta charset="utf-8">
<script>
function zdarzenie1() {
alert("załadowałem");
}
function zdarzenie2() {
alert("kliknąłem");
}
</script>
</head>
<body onload="zdarzenie1()">.
<p>Kliknij
<a href="\#" onclick="zdarzenie2()">tutaj</a>
</p>
</body>
</html>
Objaśnienie
Użyte w kodzie symbole (zobacz: Programowanie: Uczymy_się myśleć_abstrakcyjnie):
Symbol | Znaczenie | oznaczanie |
---|---|---|
function | Symbol używany do zdefiniowania fragmentu kodu (programu) nazywanego funkcją (zob. dalej). | Definicję jakiejś funkcji. |
zdarzenie1 zdarzenie2 | Symbole zdefiniowane przez nas – nazwy funkcji. | Definicje funkcji (zdarzenie1 i zdarzenie2). |
alert | Wyświetlenie komunikatu | Funkcję zdefiniowaną (wbudowaną) w przeglądarce. |
Znaki używane dla interpretera (przeglądarki internetowej) – aby mógł zrozumieć znaczenie tekstu:
Znak | Znaczenie |
---|---|
{ | Początek bloku (funkcji) |
} | Koniec bloku (funkcji) |
; | Koniec instrukcji (z których budujemy funkcję). |
" | Cudzysłów oznaczający początek i koniec napisu. |
= | Znak równości (lub nadanie zmiennej określonej wartości) |
( | Początek miejsca na parametry funkcji |
) | Koniec miejsca na parametry funkcji |
Funkcja to fragment kodu programu określony nazwą. Zamiast słowa funkcja używa się czasem określenia ‘procedura’, które nie oznacza jednak dokładnie tego samego (czasem przyjmuje się, że procedura to funkcja która nie zwraca żadnej wartości).
Znaczenie symbolu zależy od kontekstu w którym go używamy. Słowo „alert” oznacza po angielsku alarm. W środowisku przeglądarki internetowej powoduje wyświetlenie komunikatu. Użycie symbolu w powyższym zdaniu jest jego przytoczeniem (cytatem). Po to używamy cudzysłowów. Jeśli w definicji funkcji test zmienimy alert(‘kliknąłem’) na alert(‘alert’) to nie wykona się dwa razy funkcja „alert”, tylko zostanie wyświetlona (przytoczona) jej nazwa.
Kontekst jest ważny, bo w różnych miejscach ten sam symbol może oznaczać coś innego. Nie należy tego nadużywać (lepiej stosować różne symbole).
Operowanie na drzewie DOM
Obiekt dokumentu (document) posiada metody pozwalające odszukanie węzła drzewa (w praktyce stosuje się do tego rozszerzenia / bibliotekę jQuery – o czym będzie mowa dalej). Na przyład na podstawie identyfikatora (własność id).
Przykład 2:
<html>
<head>
<script>
function test() {
alert(document.getElementById("test").style.color);
}
</script>
</head>
<body>
<span style="color:blue" id="test" onclick="test();"> kliknij tutaj
</span>
</body>
</html>
W przykładzie tym kliknięcie w tekst powoduje wyświetlenie nazwy koloru. Możemy ten kolor też w JavaScript zmieniać:
document.getElementById("test").style.color = "red";
spowoduje zmianę koloru na czerwony.
Algorytmy
Komputer działa w sposób deterministyczny – to znaczy, że zawsze w danym stanie (zawartość pamięci i urządzeń wejściowych) zachowa się tak samo. Jednak wspomniany stan może się zmieniać, dlatego programy muszą przewidywać różne warianty. Służą do tego instrukcje warunkowe. Na przykład:
jeśli a>b to napisz(‘a>b’);
jeśli a<b to napisz(‘a<b’);
W językach programowania w miejsce „jeśli” pojawia się angielskie „if”.
Przykład:
<form>
rok= <input id="rok" type=text value="2016"><br />
miesiąc= <input id="mies" type=text value="01"><br />
<input type="button" onclick="javascript:licz()" value="licz"/><br >
dni= <input id='dni' type=text value="00" readonly/><br />
</form>
Javascript:
function licz(){
rok=document.getElementById('rok').value;
mies=document.getElementById('mies').value;
var dni='31';
if (mies=='02') {
dni='28';
if (rok==2016) { dni='29'; }
}
if (mies=='04') { dni='30'; }
if (mies=='06') { dni='30'; }
if (mies=='09') { dni='30'; }
if (mies=='01') { dni='30'; }
document.getElementById('dni').value=dni;
}
Inną używaną często instrukcją jest for - pozwala wykonać tą samą operację na wielu obiekach. Na przykład (https://www.w3schools.com/jsref/jsref_forin.asp):
var person = {fname:"John", lname:"Doe", age:25};
var text = "";
var x;
for (x in person) {
text += person[x];
}
jQuery
Biblioteka (czyli dołączany z zewnątrz skrypt) jQuery nie wchodzi w skład definicji JavaScript, ale jest tak powszechnie używana, że można ją traktować jako standard. Dobre wprowadzenie do tej biblioteki można znaleźć na stronie: http://shebang.pl/kursy/podstawy-jquery/r3/
Najważniejszą ideą jest całkowite oczyszczenie kodu HTML ze skryptów. Zamiast tego – po załadowaniu strony modyfikujemy drzewo DOM dodając w razie potrzeby obsługę zdarzeń.
Odwołanie do węzłów drzewa zwraca nam funkcja o nazwie $.
Zobaczmy to na prostym przykładzie .
Przykład 3a (bez jQuery):
<html>
<head>
<script>
function zaladowalem() {
document.getElementById("kolorowy1").style.color="green";
}
</script>
</head>
<body onload="zaladowalem()">.
<p>Tekst
<span id="kolorowy1" style="color:red">kolorowy</span>
</p>
</body>
</html>
Serwis jsbin.com pozwala wyłączyć javascript – po prawej. Włączając lub wyłączając możemy zobaczyć tekst czerwony lub zielony. Ten sam przykład z użycie jQuery (kod dołączenia z https://code.jquery.com):
Przykład 3b (z jQuery):
<html>
<head>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
function zaladowalem() {
kolorowy1 = $("#kolorowy1");
if (kolorowy1) {
kolorowy1.css('color', 'green');
}
}
$(document).ready(
zaladowalem
);
</script>
</head>
<body>.
<p>Tekst
<span id="kolorowy1" style="color:red">kolorowy</span>
</p>
</body>
</html>
Należy zwrócić uwagę na użycie # - tak jak w CSS. Tekst został specjalnie napisany tak, aby był łatwy do debugowania. Debugger
(odpluskwiacz) pozwala na wykonywanie programu krok po kroku. Dla JavaScript dobrym debugger ma Firefox (narzędzia dla programistów – https://developer.mozilla.org/pl/docs/Narz%C4%99dzia/Debugger).
Powyższy przykład można uprościć używając funkcji anonimowych (tam gdzie parametrem może być funkcja, można także wpisać jej definicję – a nie nazwę jak w powyższym przykładzie):
<html>
<head>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
$(document).ready(
function() {
$("#kolorowy1").css('color', 'green').css('font-weight', 'bold');
}
);
</script>
</head>
<body>.
<p>Tekst
<span id="kolorowy1" style="color:red">kolorowy</span>
</p>
</body>
</html>
Kilka uwag objaśniających.
Rezygnujemy ze sprawdzenia, czy obiekt kolorowy1 istnieje. Jeśli go nie ma – nie będzie błędu, tylko .css się nie wykona. To jedna z fajnych rzeczy w JavaScript.
Wynikiem funkcji $ jest obiekt - ale nie obiekt drzewa DOM – dlatego nie odwołujemy się do własności style, tylko wywołujemy metodę css. Tak samo obiektem jest wynik każdej metody wywoływanej na rzecz przetwarzanego obiektu. Dlatego możemy po kropce łączyć następne wywołania:
$("#kolorowy1").css('color', 'green').css('font-weight', 'bold');
Dynamiczne budowanie strony w JavaScript
Podobnie jak metoda css zmienia styl, metoda html tworzy nowe fragmenty strony:
<html>
<head>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
$(document).ready(function() {
$("#kwadracik").html("<ul>dowolny fragment</u>
strony").css('border', 'solid 1px green');
});
</script>
</head>
<body>.
<div id="kwadracik"></div>
</body>
</html>
Jeśli parametrem funkcji $ nie jest selektor wyboru obiektów (np. identyfikator) ale HTML, to funkcja tworzy nowy obiekt. Można go później dołączyć w dowolne miejsce strony:
<html>
<head>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
var nowy = $('<div>drugi</div>');
$(document).ready(function() {
$("#kwadracik").html("<ul>dowolny fragment</u> strony").css('border', 'solid 1px green');
nowy.appendTo('#kwadracik');
});
</script>
</head>
<body>.
<div id="kwadracik"></div>
</body>
</html>
Struktury, JSON
Jako parametr funkcji $().css() można podać kolekcję atrybutów do zmiany:
<html>
<head>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
$(document).ready(function() {
$("#kolorowy1").css({
'color': 'green',
'font-weight': 'bold'
});
});
</script>
</head>
<body>
<p>Tekst
<span id="kolorowy1" style="color:red">kolorowy</span>
</p>
</body>
</html>
Taka struktura ujęta w nawiasy klamrowe jest złożonym typem danych, który w JavaScript nazywa się obiektem (w innych językach odpowiada temu rekord). Definiujemy go podając rozdzielone przecinkiem pary: nazwa własnosci : wartość własności. Innym typem danych jest lista (tablica) – czyli zbiór wartości oddzielonych przecinkiem. Opisuje się go nawiasami
kwadratowymi []:
var liczby = [1,2,3,4,5];
Więcej http://shebang.pl/kursy/wszystko-jasne/r4-obiekty-tablice/
Opis struktur stosowany w JavaScript został przyjęty jako standard w komunikacji internetowej jak JSON. Należy jednak pamięać, że JSON to tekst, a nie obiekt. Napis '{"wlasnosc":"wartość"}' jest poprawnym tekstem JSON. Jeśli wczytamy go do zmiennej "zmienna", to nie uzyskamy możliwości dosępu do wartości poprzez zapis: zmienna.wlasnosc. Biblioteka jQuery zawiera funkcję parseJSON pozwalającą zapis zamienić na strukturę:
<html>
<head>
<meta charset="utf-8">
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
$(document).ready(function() {
var zmienna = $.parseJSON( '{"wlasnosc":"wartość"}' );
alert( zmienna.wlasnosc );
});
</script>
</head>
<body>.
</body>
</html>