JavaScript ja DOM
- Luentotaltiointi
- Työvälineet
- Historiaa
- JavaScript-tiedoston linkittäminen
- Syntaksi
- Tarpeellisia funktioita
- Tapahtumat
- Document Object Model (DOM)
- Esimerkkejä
- Huomioitavaa
Käsitellään JavaScriptin ja DOM:n käyttöä WWW-sovelluksissa.
Työvälineet
- Eclipse
- Notepad++
- Firebug
- Viestit komentoriville (
console.log(message)
) - Debuggaus selaimessa (Error console)
- DOM-inspector
- Viestit komentoriville (
Historiaa
Javascript on alunperin kehitetty Netscape-selaimeen 1990-luvulla. Microsoft kehitti oman versionsa nimeltään JScript vähän Netscapen jälkeen. Javascript-kieli on standardoitu ECMAScript-standardissa. ECMAScript-kieltä kehitetään edelleen. Tällä hetkellä on käytössä Javascript 1.8 (Firefox 2).
Eri Javascript-versioita:
- Javascript 1.5
- Javascript 1.6
- Uusia ominaisuuksia Array-objektiin
- Javascript 1.7
- Iteraattorit
- Lohkokohtaiset muuttujat
- Funktiot voivat palauttaa moniarvoisia tuloksia
- Javascript 1.8
Javascript-yhteensopivuus on aina ollut hieman ongelmallista mutta nykyään asia voidaan hoitaa käyttämällä valmiita kirjastoja.
JavaScript-tiedoston linkittäminen
script
-elementillä head-osassa:
<script type="text/javascript" src="jokutiedosto.js"></script>
Syntaksi
Javascriptin syntaksista kannattaa lukea seuraavia lähteitä:
Ympäristö
JavaScriptiä suoritetaan määrätyssä ympäristössä, joka voi olla esimerkiksi selaimessa. JavaScript ei itsessään määrittele, miten tietoa voidaan syöttää tai tulostaa, vaan se tarjoaa ainoastaan tiedon käsittelymekanismit. Tiedon syöttö ja vasteiden anto tehdään käyttäen XHTML:ää ja DOM:ia.
Yleistä
- Isoilla ja pienillä kirjaimille on merkitystä (Foo on eri kuin foo)
- Rivit päättyvät puolipisteeseen (;). Javascript ei kuitenkaan kaikissa tilanteissa kaipaa puolipistettä (;) rivin loppuun. On erittäin suositeltavaa käyttää puolipistettä aina!
- Kommentit merkitään kuten C++:ssa: // ja /* */
Muuttujat
JavaScript on heikosti tyypitetty kieli. Muuttujien tyyppi määräytyy siis arvon perusteella. Muuttujat esitellään seuraavasti:
var x = 1.0; var s = "Diiba daaba"; totuus = true; // globaali muuttuja, näkyy kaikissa funktioissa
Huomioi seuraavaa:
- Liukulukujen tarkkuus n.15 desimaalia.
0.2 + 0.1111 = 0.31110000000000004
Tulos on pyöristettävä sopivaan tarkkuuteen. - Muuttujan näkyvyys rajoittuu funktion sisälle, jos muuttuja esitellään var-etuliitteellä
- Muuttujalla voi olla myös muutama erikoisarvo:
- NaN - not a number
- Infinity ja -Infinity - äärettömyydet
- null - viittaus tyhjään. null on objekti
- undefined - arvoa ei määritelty. Ei ole sama asia kuin null. undefined ei ole objekti.
if ( typeof(x) == 'undefined')
- Three common mistakes in JavaScript
Operaattorit
Käytössä on normaalit aritmeettiset ja vertailuoperaattorit.
- 0, tyhjä merkkijono, NaN, null ja undefined ovat loogisissa operaatioissa totuusarvoltaan false, kaikki muut true
- !! antaa muuttujan totuusarvon
- Matemaattisia operaatioita varten on olemassa globaali objekti Math
- === tarkistaa ovatko saman arvoiset ja samaa tyyppiä. Käytä tätä jos yrität tutkia onko jokin null tai undefined
Merkkijonot
Merkkijonot ovat olioita, joilla mm. seuraavia metodeja:
Merkkijonoja voi operoida seuraavilla operaattoreilla:
- +
- Liittää merkkijonot yhteen
- < > <= >= ==
- Vertailee aakkosjärjestystä
- s[n]
- Antaa merkkijonon s n:nnen kirjaimen
Merkkijonojen tyyppien muunnoksiin on olemassa muutama globaali funktio:
var luku = parseInt("567");
var luku = parseInt("567", 10); // toinen argumentti kertoo kantaluvun. Tässä kymmenjärjestelmä
var luku = parseInt("0567"); // ei toimi kuten voisi kuvitella. etunolla tarkoittaa, että luku saatetaan käsitellä oktaalijärjestelmässä.
var luku = parseInt("0567", 10); // tämä toimii
var luku = parseInt("101", 2); // binääriluku
Taulukot
Taulukko luodaan Array-oliolla
var paikat = new Array(); paikat[0] = "Jämsä"; paikat[1] = "Äänekoski";
tai hakasulkeilla:
var paikat = ["Jämsä", "Äänekoski"];
- Taulukon indeksinä on aina numero.
- Taulukon viimeistä seuraavan indeksin saa taulukko.length -metodilla.
Taulukkoon lisääminen onnistuu seuraavasti:
paikat[paikat.length] = "Jyväskylä"; paikat.push("Jyväskylä");
Assosiatiivisia "taulukoita" (nimi-arvo-pareja) voi tehdä seuraavasti:
var lampo = new Object; lampo["jkl"] = -6; var saatilat = { jämsä: "Aurinkoinen", äänekoski: "Pilvipoutaa" }; for (var i in saatilat) { alert( i + " : " + saatilat[i] ); }
Assosiatiivinen "taulukko" on itseasiassa olio, jolla on attribuutteja. Tämä voi aiheuttaa jossain tilanteissa hämmennystä.
Funktiot
Funktion voi esitellä seuraavasti:
function summaa(x,y) { return (x + y); } summaa = function(x,y) { return (x + y); }
Huomioitavaa:
- Funktiota voi kutsua ylimääräisillä parametreilla. Kaikki funktion saamat parametrit voi käydä läpi arguments-taulukolla.
- Jos funktio ei palauta return-lauseella arvoa on funktion palautusarvo undefined
Oliot
JavaScript (joka pohjautuu Ecmascript 3 -standardiin) on prototyyppi-pohjainen kieli ja siinä ei ole luokkia samassa mielessä kuin Java/C++/C#-kielissä vaan pelkästään olioita (objekteja). JavaScriptissä omia olioita voidaan luoda seuraavasti:
// konstruktori-funktio function Koordinaatti(x,y) { this.x = x; this.y = y; } // Koordinaatin "public-metodi" Koordinaatti.prototype.normi = function() { return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2)); } var piste = new Koordinaatti(1,2); piste.normi();
Olioita laajennetaan toisten olioiden avulla käyttäen prototype-määritystä. Private-attribuutteja ja -metodeja on mahdollista luoda pienellä vaivalla.
Ohjausrakenteet
Javascriptissä on normaalit ohjausrakenteet:
Tarpeellisia funktioita
Aika
- Globaalit oliot: Date - Core JavaScript 1.5 Reference
Päivämäärä
var aika = new Date(); alert(aika.getDate() + "." + aika.getMonth() + "." + aika.getYear());
Kulunut aika
var aika = new Date(); var hetkiA_msec = aika.getTime(); // tehdään jotain var hetkiB_msec = aika.getTime(); var kulunutaika = new Date(hetkiB_msec - hetkiA_msec); alert(kulunutaika.getSeconds());
Ajastetut funktiot
-
window.setInterval
-
window.setTimeout
// suoritetaan oma_ajastettu_funktio joka sekunti window.setInterval(oma_ajastettu_funktio,1000);
Math
- Globaalit oliot: Math - Core JavaScript 1.5 Reference
Pyöristäminen
var liukuluku = 3.245200004; var kaksidesimaalia = Math.round(liukuluku*100)/100
Satunnaisluvut
var sanoja = ["Diiba","Daaba","Tesmaus","Heppa","Muuli","Saippuakauppias","Jepjep"]; // pyöristys alaspäin( 0-0.999999999 * 7 ) var rand = Math.floor( Math.random() * sanoja.length ); console.log(sanoja[rand]);
eval
Funktiot: eval - Core JavaScript 1.5 Reference
Esimerkki:
// XHTML-dokumentissa <p><span id="lasku">3 + 4</span> = <strong id="tulos"></strong></p> // JavaScript-funktiossa var yhteenlasku = document.getElementById("lasku").firstChild.nodeValue; var tulos = eval(yhteenlasku); document.getElementById("tulos").firstChild.nodeValue = tulos;
Toinen esimerkki:
// XHTML-dokumentissa <p><input type="text" id="funktio" onchange="suorita" /></p> // JavaScriptissä: function ykkonen() { alert("Funktiossa ykkonen!"); } function kakkonen() { alert("Funktiossa kakkonen!"); } function suorita() { var funktion_nimi = document.getElementById("funktio").value; eval(funktion_nimi + "()"); }
eval
on hidas verrattuna normaaleihin laskutoimituksiin ja funktiokutsuihin
isNaN
Tutkii onko muuttuja erikoisarvoa NaN (not a number). NaN-arvoa ei voi vertailla muulla kuin tällä funktiolla.
var numero = parseInt(document.getElementById("tekstikentta").value); if (isNaN(numero)) document.getElementById("tekstikentta").className = "red";
typeof
Operaattorit: typeof - Core JavaScript 1.5 Reference
Palauttaa stringinä muuttujan tyypin.
Tapahtumat
Javascript-funktioiden suoritus kytketään tiettyyn tapahtumaan, esimerkiksi kun sivu on ladattu tai käyttäjä tekee jotain. XHTML-elementeille voi antaa ominaisuuksia, jotka liittyvät tiettyyn tapahtumaan. Ominaisuuden arvoksi annetaan haluttu funktio. Esim.
<input onchange="laske_arvosana()" id="vt1" size="3" maxlength="3" value="0" />
Tapahtumia ei yleensä kannata määrätä kiinteästi elementteihin, sillä kaikissa selaimissa ei ole JavaScript-tukea. Tapahtuman voi määrätä myös erillisessä Javascript-tiedostossa seuraavasti:
elementti.tapahtumatyyppi = käsittelijäfunktio;
Selaimen tarjoamiin globaaleihin olioihin voi myös määrätä tapahtumia, esim.
window.onload = function() { // sivun latauksen jälkeen tapahtuvat toimenpiteet }
Seuraavassa dokumentissa on lista erilaisista tapahtumista selitteineen:
- Tapahtumankäsittely (XHTML Intrinsic Events Module)
Ylläolevissa esimerkeissä tapahtumankäsittelijäksi voi määrätä vain yhden funktion. DOM-standardi määrittää kuitenkin paremman tavan tapahtumien rekisteröinnille ja mahdollistaa useiden tapahtuman käsittelijöiden liittämisen tapahtumaan:
elementti.addEventListener(tapahtumantyyppi, käsittelijäfunktio, kaappaus);
- tapahtumantyyppi on jokin HTML Events tai DOM-standardissa määritelty merkkijono, esim.
change, click, keyup, blur
jne. - käsittelijäfunktio on funktion nimi, jota kutsutaan kun määrätty tapahtuma on tapahtunut (tarkkaanottaen funktio on EventListener-rajapinnan toteuttava olio)
- kaappaus on boolean-arvo, joka kertoo käytetäänkö tapahtuman kaappausta. Aseta tähän kohtaan true vain kun asetat tapahtumankäsittelijän elementin esivanhempielementille.
Tarkempaa tietoa missä järjestyksessä tapahtumat käsitellään:
Esim. tapahtumankäsittelijän kytkeminen useaan elementtiin:
window.onload = function() { for(var i=1;i<=9;i++) { document.getElementById("vt" + i).addEventListener("change", laske_arvosana, false); } }
Tästä on myös sekin etu, että rekistöidyssä funktiossa saa viitattua
tapahtuman aiheuttaneeseen elementtiin this-muuttujan avulla
(tai evt.target
:lla) ja yhteen tapahtumaan voidaan liittää
useita tapahtuman käsittelijöitä.
Oletustapahtuman voi peruuttaa kutsumalla e.preventDefault()-funktiota.
Tapahtuman välittymisen muille käsittelijöille voi estää kutsumalla e.stopPropagation()-funktiota
Tapahtumien rekisteröintiin on myös olemassa funktioita, jotka korjaavat selaimien väliset erot:
- AddEvent() - Follow Up - Dean Edwards
- Flexible Javascript Events - John Resig
- Advanced event registration models
Selaimien välillä on muitakin yhteensopivuusongelmia, joten samalla vaivalla kannattaa ottaa käyttöön jokin kirjasto, joka hoitaa likaisen työn. Näitä kirjastoja tarkastellaan Ajax-luennon yhteydessä.
Document Object Model (DOM)
DOM on standardi, jonka avulla voidaan manipuloida dynaamisesti dokumenttipuuta.
Dokumentin rakennetta voi tutkia esim. Firebugin HTML-välilehdeltä.
Kukin elementti ja teksti muodostavat dokumenttipuuhun Node-tyypin olion. DOM:in tarjoamia attribuutteja ja metodeja voi tarkastella
Firebugin DOM-välilehdeltä. Valitse aluksi esim. document
ja sen alta documentElement
, niin pääset tutkimaan html
-elementtiä.
Käsitteitä
- vanhempi-, äiti- tai isäelementti (engl. parent)
- elementti, jonka sisällä ko. elementti välittömästi on.
- lapsielementti (engl. child)
- välittömästi ko. elementin sisällä oleva elementti
- jälkeläinen (engl. descendant)
- ko. elementin sisällä oleva elementti
- esivanhempi, esiisä (engl. ancestor)
- elementti, jonka jälkeläinen ko. elementti on
- sisarelementti (engl. sibling)
- elementit ovat sisaret, jos niillä on yhteinen vanhempielementti
- edeltävä/seuraava sisarelementti (engl. preceding/following sibling)
- edeltävä elementti on dokumenttipuussa ennen ko. elementtiä, seuraava on sen jälkeen
JavaScript kytkeytyy DOM:iin mm. seuraavien olioiden ja metodien kautta:
Elementtien saanti
-
document.getElementById(id)
document.documentElement
document.body
-
element.getElementsByTagName(name)
element.parentNode
element.firstChild
element.lastChild
element.childNodes
element.nextSibling
Elementtien lisääminen ja poistaminen
-
document.createElement(name)
document.createTextNode(data)
-
element.appendChild(node)
element.insertBefore(node)
element.removeChild(node)
element.replaceChild(newChild, oldChild)
Esim.
var vanhaelementti = document.getElementById("elementin_id"); vanhaelementti.parentNode.replaceChild(uusielementti, vanhaelementti);
element.innerHTML
- Ei kuulu DOM-standardiin, mutta on useissa selaimissa. Ei pidä käyttää, koska voi rikkoa DOM-puun.
Elementtien arvot
element.nodeValue
HTMLInputElement.value
jaHTMLSelectElement.value
HTMLSelectElement.selectedIndex
- DOM Level 1element.textContent
- DOM Level 3, ei toimi IE:ssäelement.nodeName
-
element.setAttribute(name, value)
-
element.getAttribute(name)
element.className
element.style
document.defaultView.getComputedStyle(element,pseudoelement).getPropertyValue(stylename)
Huomattavaa
- DOM:in käsittely on "live" eli jos esimerkiksi olet läpikäymässä jonkun solmun lapsielementtejä ja poistat sieltä yhden niin läpikäytävä joukko muuttuu.
- Solmun siirtäminen tapahtuu hakemalla haluttu solmu ja liittämällä se toisen solmun lapsisolmuksi
appendChild
-metodilla. Normaalisti solmuista ei tule kopioita vaan olioreferenssit liikkuvat vain vanhempielementiltä toiselle. - Teksti ei ole normaalin elementtisolmun ominaisuus vaan elementin
sisällä on usein
TextNode
-tyyppinen solmu, jonka tekstisisällön saaNodeValue
-metodilla. Lomakekomponenttien arvot - Puun läpikäyminen vaatii usein rekursiota.
- Helpoin tapa saada tietty elementti on antaa sille
id
-arvo ja pyytää sitädocument.getElementById
-metodilla. - Monet metodit, kuten
getElementsByTagName
, palauttavat listan solmuista, nämä pitää läpikäydä silmukassa ja pyytää yksittäin listaobjekti.item(i)
metodilla - Tietyn elementin voi poistaa vain sen vanhempielementti. Esim. tietyllä id:llä olevi kaikkien lapsielementtien poistaminen:
var vanhempi = document.getElementById("lista"); while (vanhempi.firstChild) { vanhempi.removeChild(vanhempi.firstChild); }
Lisätietoa
- Gecko DOM Reference
- DOM Tool - helpottaa elementtien luomista
- W3C DOM
- DOM HTML - HTML-elementtien erityisominaisuudet
Esimerkkejä
Esimerkit luennolla 4.
Huomioitavaa
Javascriptin ja DOMin käytössä tulee huomioida seuraavat asiat:
- Selain ei välttämättä tue JavaScriptiä ollenkaan tai se on kytketty
pois päältä. Sovelluksen on silti toimittava järkevästi. Esimerkiksi
- Lomakkeen validointi on tehtävä myös palvelinpäässä
- Sivun käyttöliittymän on toimittava ilman javascriptiä.
Käyttäjien kommentit