JavaScript ja DOM - Luento 13
- 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.
Luentotaltiointi
- sovellukset13.mp3 16M
- sovellukset13.wmv 46M
- sovellukset13.avi 175M
Työvälineet
- Eclipse
- Firebug
- Viestit komentoriville (
console.log(message)) - Debuggaus selaimessa
- 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.7 (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-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.
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
- undefined - arvoa ei määritelty
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ä
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.
Funktiot
Toimii kuten PHP:ssa. 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 kuten PHP:ssa. Kaikki funktion saamat parametrit voi käydä läpi arguments-taulukolla.
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());
ISO-päivämäärän (YYYY-MM-DD hh:mm:ss) saa Date-tyypin olioksi MochiKitin DateTime-metodeilla.
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 normaaliin 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, blurjne. - 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.documentElementdocument.body-
element.getElementsByTagName(name) element.parentNodeelement.firstChildelement.lastChildelement.childNodeselement.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.
Elementtien arvot
element.nodeValueHTMLInputElement.valuejaHTMLSelectElement.valueHTMLSelectElement.selectedIndex- DOM Level 1element.textContent- DOM Level 3, ei toimi IE:ssäelement.nodeName-
element.setAttribute(name, value) -
element.getAttribute(name) element.classNameelement.styledocument.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 14.
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
Assosiatiivisia taulukoita _voi_ käydä läpi: var saatilat = {"jämsä": "Aurinkoinen","äänekoski": "Pilvipoutaa"}; for(var i in saatilat) { alert(i+": "+saatilat[i]); } Näyttää toimivan myös IE7:ssa.