Uvod
Pomenuli smo u prvom članku uvodnog serijala o web dizajnu da jezici HTML, CSS i Javascript čine svojevrsno "sveto trojstvo" internet jezika, odmah se upustili u proučavanje prva dva jezika i čitaocima preporučili da se izučavanju Javascript-a posvete tek pošto dobro savladaju osnove HTML-a i CSS-a.
Ukoliko čitate ove redove, pretpostavićemo da ste savladali osnove HTML-a i CSS-a i da je došao trenutak da počnete da proučavate Javascript, pa ćemo u nastavku napraviti presek osnovnih mogućnosti ovog jezika.
Neko manje upućen rekao bi možda da je Javascript jezik koji se povezuje sa HTML-om i figurativno (u prenesenom smislu), možemo reći da je tako, ali u pravom smislu reči - Javascript se zapravo povezuje sa strukturom podataka koja nastaje iz HTML koda pri učitavanju dokumenta u browser, s tim da naravno takva struktura (za razliku od HTML-a) nije obična niska znakova, već posebno dizajnirano stablo.
Pomenuta struktura nosi naziv Document Object Model, ili skraćeno - DOM.
Document Object Model (DOM)
Sadržaj web stranica prenosi se od servera do klijenta u obliku HTML koda, međutim, koliko god tekst bio prikladan način za daljinski prenos informacije o strukturi sajta, browseri ne skladište podatke neophodne za prikaz stranice u izvornom obliku.
Umesto toga, HTML kod se koristi za izgradnju strukture stabla koje predstavlja strukturu stranice:

U korenu navedenog stabla nalazi se sam dokument (figurativno - browser), odmah ispod je čvor koji predstavlja <html>
tagove, direktno ispod su čvorovi koji predstavljaju tagove <head>
i <body>
i tako redom, do nižih nivoa hijerarhije, to jest, do čvorova koji nemaju potomke.
Svakom čvoru pripisan je i odgovarajući sadržaj.
Da bismo sve to razumeli što bolje, razmotrićemo sledeći jednostavan HTML kod ....
<!DOCTYPE html>
<html>
<head>
<title>DOM Struktura</title>
<meta charset='UTF-8'>
<link rel='stylesheet' href='stil.css'/>
</head>
<body>
<h1>DOM Struktura</h1>
<p>
Prvi pasus
</p>
<p>
Drugi pasus
</p>
</body>
</html>
.... i DOM stablo koje nastaje iz prikazane HTML strukture:

Stablo sadrži celokupnu strukturu dokumenta (tekstualni sadržaj svih tagova i vrednosti svih atributa) i što je najvažnije - ovakva struktura omogućava znatno brži i efikasniji pristup elementima.
Programski jezik preko koga se pristupa elementima unutar DOM stabla i preko koga se obavljaju različite operacije nad elementima je (kao što već znate) - Javascript.
Osnove jezika Javascript
Javascript je skriptni programski jezik visokog nivoa koji (preko DOM modela), omogućava pristup elementima stranice, obradu (odnosno izmenu) elemenata, asinhronu komunikaciju sa serverom preko specijalizovanih XmlHttpRequest
objekata (time ćemo se ipak baviti u nekom od budućih članaka), kao i obavljanje brojnih drugih zadataka.
Ovaj jezik pojavio se sredinom devedesetih godina dvadesetog veka i u početku je nudio znatno manje mogućnosti nego danas, ali su tokom vremena mogućnosti jezika proširivane i Javascript je stekao veliku popularnost.
Na popularnost Javascript-a posebno je uticala pojava radnog okruženja Node JS (cca. 2009), koje je omogućilo pokretanje desktop aplikacija napisanih u Javascript-u (što prethodno nije bio slučaj; Javascript je bio isključivo web jezik).
Javascript sadrži kontrolne strukture kakve srećemo u C-u i srodnim programskim jezicima (matematičke operatore, operatore poređenja, uslovne naredbe, petlje, funkcije, objekte), ali - kada se pokreće u browseru - JS ne omogućava pristup sistemskim resursima računara klijenta.
Javascript se sa HTML datotekama povezuje preko <script>
tagova (datoteke u kojima čuvamo skripte koje pišemo preko jezika Javascript, imaju ekstenziju .js
):
<body>
<!--
Sadržaj stranice
....
-->
<script src='skripta.js'></script>
</body>
Tagove <script>
ćemo za potrebe primera u ovom članku smestiti unutar <body>
tagova, na samom kraju (posle svih ostalih sadržaja, onako kako smo već videli).
Inače se <script>
tagovi mogu smestiti i unutar <head>
tagova (što je zapravo pristup koji se tipično koristi, ali, objasnićemo u nastavku u čemu je razlika i zašto smo za ovaj članak napravili drugačiji izbor).
Za početak (kako i dolikuje), "hello world" program. Ukoliko unutar JS dokumenta koji smo povezali sa HTML datotekom unesemo sledeći kod:
document.write("Dobar dan!");
.... nećemo se previše "usrećiti", jer će skripta poništiti strukturu već učitanog HTML dokumenta (ali će bar uredno ispisati pozdravnu poruku). :)
Javascript (kao što smo nagovestili) ima pristup DOM strukturi, a preko skripte koju smo napisali, direktno smo pristupili korenom elementu DOM strukture i zadali sadržaj (čime je poništen postojeći sadržaj), ali to što se desilo je samo pouka i sada znamo da je potrebno da budemo precizniji (to jest, da moramo izabrati konkretan HTML element na stranici, kome potom možemo pripisati određeni sadržaj).
Međutim, ako samo želimo da ispisujemo poruke, postoje i drugi načini.
Ispis poruka (alert i console.log)
Umesto "poništavanja" sadržaja DOM strukture (kao u prethodnom odeljku) i pre nego što razmotrimo kako se poruke mogu prosleđivati postojećim HTML elementima (zapravo - kako se postojećim elementima može pripisati određeni HTML sadržaj), razmotrićemo još i načine slanja poruka korisniku preko funkcija alert
i console.log
.
Funkcija alert
....
alert("Dobar dan!");
.... poziva otvaranje prozora sa porukom koja je predata kao argument, pri čemu je bitno uočiti da prozor koji se otvara blokira pristup elementima stranice (naravno, dok ga ne zatvorimo).
Za probu, kliknite na donje dugme:
Funkcija alert
tipično se koristi za ispis "kritičnih" poruka (poruke o sadržajima koji su nedostupni i sl), ali se u pojedinim situacijama koristi i za poruke opšteg tipa (na primer, ako Javascript koristite za kreiranje igara za browser, možete korisnicima slati poruke o pređenom nivou/igri i sl).
Za ispis poruka mogu se koristiti i postojeći HTML elementi na stranici (kao što ćemo videti u sledećem odeljku), po mogućnosti oni koje smo unapred odredili za ipis poruka, ali se poruke mogu slati i u konzolu browsera, preko funkcije log
:
console.log("Dobar dan!");
Greške se mogu (ukoliko smatramo da o njima ne treba direktno obavestiti korisnika preko funkcije alert
- ali da je potrebno da postoji informacija o tome da je do greške došlo), proslediti i preko konzole:
console.error("Opcija je dostupna samo na mobilnim uređajima!");
Razlika u odnosu na funkciju console.log
je u tome što je poruka ispisana preko funkcije console.error
formatirana crvenom bojom (tamno crvena slova i crveni okvir).
Za isprobavanje funkcija console.log
i console.error
možete iskoristiti donje dugme:
(Nemojte zaboraviti da otvorite konzolu, da biste mogli da vidite rezultat.)
Pristup DOM elementima preko id-a (getElementById)
Verovatno najkorišćeniji način pristupa elementima podrazumeva pristup preko pripisanih id-ova (a budući da elementi koje smo prethodno definisali nemaju pripisan id, to je prvo što ćemo prepraviti):
<body>
<h1>DOM Struktura</h1>
<p id='prvi_pasus'>
Prvi pasus
</p>
<p id='drugi_paus'>
Drugi pasus
</p>
</body>
.... pri čemu će se i DOM struktura takođe promeniti (prikazujemo samo jedan pasus):

Sada možemo pristupiti (na primer) prvom pasusu:
document.getElementById("prvi_pasus").innerHTML = "Dobar dan! :) Ovo je prvi pasus.";
Koristili smo u svemu svojstvo innerHTML
i zaista, ono što unosimo je HTML (možemo direktno unositi HTML tagove i time redefinisati strukturu elemenata kojima pristupamo)
Da bismo to što bolje razumeli, razmotrićemo još jedan jednostavan primer, preko koga ćemo se upoznati i sa kontrolnim strukturama jezika i upotrebom promenljivih.
Kontrolne strukture Javascript jezika i promenljive (var)
Pre nego što se upoznamo sa navedenim elementima jezika, dodaćemo sadržaj u datoteku "stil.css" (da se podsetimo, u HTML primeru koji koristimo već je naveden tag <link>
, za povezivanje sa CSS-om):
.plavi_pasus {
width: 120px;
height: 120px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: #7788ee;
color: #fff;
font-family; Arial, sans-serif;
font-size: 18pt;
margin: 0 12px 0 0;
}
.... posle čega se možemo vratiti na Javascript i uneti sledeće izmene:
var i;
var brojPasusa = 4;
var sadrzajPasusa = "";
for (i = 1; i <= brojPasusa; i++) {
sadrzajPasusa += "
<div class='plavi_pasus'>" + i + "</div>
\n";
}
document.getElementById("prvi_pasus").innerHTML = sadrzajPasusa;
Promenljive se definišu preko rezervisane reči var
, a Javascript je, kao što možemo videti, jezik sa dinamičkom tipizacijom (pri deklaraciji promenljivih se ne zadaje tip promenljive, već se tip određuje automatski pri prvoj naredbi dodele).
Sledeće što možemo zapaziti je vrlo "liberalno" povezivanje string konstanti (običnog teksta koji smo mi sami ispisali) i vrednosti promenljivih brojevnog tipa, koje se u toku izvršavanja skripte automatski pretvaraju u tekst (mislimo pri tom na sledeći odeljak):
sadrzajPasusa += "<div class='plavi_pasus'>" + i + "</div>\n";
.... što nije slučaj sa većinom drugih jezika, gde se komanda za pretvaranje broja u nisku mora eksplicitno navesti.
Pre nego što nastavimo, pogledaćemo kako primer koji smo prethodno definisali funkcioniše u praksi (kliknite na dugme):
JS kod koji je zapisan izvan funkcija poziva se (svaki put) pri pokretanju skripte, što može biti upravo ono što želimo da izvedemo, a može biti i nešto što želimo da izbegnemo.
Kod zapisan unutar funkcija izvršava se samo kada funkcije pozovemo, a naravno možemo udesiti i da se pozivi funkcija poklope sa određenim događajima na stranici.
Događaji (events) i funkcije
Za primer ćemo uzeti tipičnu situaciju u kojoj je određeni blok programskog koda potrebno pokrenuti kada korisnik klikne na dugme (što će biti registrovano preko događaja onclick
):
<body>
<p>
Prvi pasus
</p>
<p>
Drugi pasus
</p>
<button onclick='dodavanjePasusa()'>KLIK</button>
</body>
U konkretnom primeru, svaki put kad korisnik klikne na dugme biće pozvana funkcija dodavanjePasusa
.
Da bi klik imao pravog efekta, u skripti ćemo definisati funkciju dodavanjePasusa
i u telo funkcije premestiti celokupan kod koji smo prethodno definisali:
function dodavanjePasusa() {
let i;
let brojPasusa = 4;
let sadrzajPasusa = "";
for (i = 1; i <= brojPasusa; i++) {
sadrzajPasusa += "
<div class='plavi_pasus'>" + i + "</div>
\n";
}
document.getElementById("prvi_pasus").innerHTML = sadrzajPasusa;
}
Sada je kod spreman i neće se pokretati sam od sebe (već samo onda kada kliknemo na dugme).
Pozicija script tagova unutar HTML dokumenta
Pozicija <script>
tagova unutar HTML dokumenta i te kako ima uticaja na korektnost izvršavanja JS koda, budući da se HTML tagovi učitavaju redom, što važi i za kod učitan preko <script>
tagova koji se izvršava odmah po učitavanju (spoljne JS datoteke se u tom smislu tretiraju kao kod koji je direktno upisan unutar <script>
tagova).
Da smo u gornjim primerima, koji koriste funkciju getElementById
, tagove <script>
smeštali unutar tagova <head>
, Javascript kod bi bio učitan i pokrenut odmah (budući da je zapisan izvan funkcija), pa bi sledeća naredba ....
document.getElementById("prvi_pasus")
.... praktično pozivala element koji ne postoji!
Dakle: ako pozivamo funkciju getElementById
unutar koda koji se automatski pokreće pri učitavanju stranice, takav kod mora se pojaviti posle HTML koda kojim se definiše objekat (u većini situacije je najpraktičnije da to bude - onako kako smo videli - na samom kraju unutar <body>
tagova).
Pogledaćemo i ostale načine pristupa elementima DOM stabla.
Pristup DOM elementima preko CSS selektora (querySelector i querySelectorAll)
Preko funkcije querySelectorAll
....
document.querySelectorAll("div > img.slika_sa_okvirom")
.... možemo unutar DOM stabla pronaći sve elemente na koje se odnosi selektor koji je u obliku niske predat kao argument (u gornjem primeru, selektor se odnosi na sve img
tagove sa klasom slika_sa_okvirom
koji se nalaze direktno unutar div
tagova). Međutim, budući da takvih elemenata može biti više, pristup elementima nije jednostavan kao u slučaju kada smo (jedan) element tražili preko id-a.
Funkcija getElementById
vraća jedan objekat (sada znamo zašto je jako bitno da id bude jedinstven!), dok naredba querySelectorAll
vraća listu elemenata koji odgovaraju kriterijumu pretrage, pa se mora koristiti i malo drugačiji mehanizam pristupa:
var slike = document.querySelectorAll("div > img.slika_sa_okvirom");
var i;
for (i = 0; i < slike.length; i++) {
slike[i].style.border = "solid 2px #77ee88";
}
Objekat slike
je referenca na listu pronađenih elemenata (koji odgovaraju prethodno navedenom CSS selektoru), pri čemu se lista kreira bez obzira na to da li elementi na koje se selektor odnosi postoje, ili ne postoje:
- kada nema elemenata za koje selektor važi, lista će biti prazna
- kada postoji samo jedan element za koji selektor važi, lista će imati jedan element (neće biti vraćen običan objekat)
- kada postoji više elemenata za koje selektor važi, biće vraćena lista sa više elemenata
Ukoliko smo skroz sigurni da postoji samo jedan element koji može biti pronađen, možemo mu pristupiti na jednostavniji način:
var slika = document.querySelector("div > img.slika_sa_okvirom");
Funkcija querySelector
vraća objekat (nije u pitanju lista), a čak i ako se "pređemo" sa ovakvim pristupom, neće biti strašno:
- ukoliko ne postoji ni jedan element koji odgovara navedenom selektoru, objekat
slika
imaće vrednostnull
- ukoliko postoji više elemenata koji odgovaraju selektoru, biće izabran prvi
.... ali, na nama je da pazimo da ne dođemo u situaciju #2 ako nam trebaju svi elementi, a ne samo jedan/prvi (to jest, da budemo sigurni da pozivamo selektor koji se odnosi na jedinstveni objekat).
Pristup DOM elementima preko pripisane klase (getElementsByClass)
Za pristup elementima preko pripisane klase možemo koristiti funkciju getElementsByClass
(s tim da u praksi, većina programera radije koristi naredbu querySelectorAll
, koja funkcioniše po istom principu, ali, nudi više mogućnosti).
Sledeći kod:
var nav_linkovi = document.getElementsByClass("nav_linkovi");
.... pronaći će sve elemente kojima je pripisana klasa nav_linkovi
i kreirati listu (koju takođe možemo obraditi onako kako smo videli u prethodnom odeljku).
Pristup DOM elementima preko opštih tagova (getElementsByTagName)
Na kraju, elementima možemo pristupati i preko opštih odrednica za tagove preko naredbe getElementsByTagName
(ali opet - i u ovom slučaju se isti efekat može postići korišćenjem naredbe querySelectorAll
).
Sledeći kod:
var naslovi_h2 = document.getElementsByTagName("h2");
.... pronaći će sve h2
naslove unutar dokumenta i (ponovo) kreirati listu (kojoj možemo pristupati na način koji smo već prikazali).
Sledeći koraci ....
Opcije koje smo prikazali u članku predstavljaju (kao što možete pretpostaviti) samo mali deo onog što Javascript nudi.
U člancima koje pripremamo za blisku budućnost, govorićemo o Node JS okruženju, ES6 sintaksi, kao i mnogim drugim temama vezanim za Javascript.
Do tada: ....