Andrise programmeerimisalane WIKI

Sündmuste haldus

NB! tegu on mustandiga! See leht täieneb nii nagu mul parasjagu aega on.

DOM level 0

DOM level 0 ei ole mitte tegelik standard, vaid nii nimetatakse netscape Navigator 2 poolt tutvustatud dokumendi objektimudelit, mida toetavad täiel määral kõik kasutuselolevad brauserid. DOM level 0 tõi kaasa ka sündmuse (ing event) mõiste, mis tähendab et lehel olev skript saab registreerida mingi sündmuse toimumist kuulama nn. sündmuse haldaja (n: hiireklikk mõnel elemendil, lehe laadimise lõpetamine, brauseri akna suuruse muutumine jne).

Selliselt defineeritud skript ei tee mitte midagi enne kui antud sündmus pole toimunud, seniks hoitakse mälus vaid pointerit skripti skoobi juurde. Kui aga sündmus toimub (kasutaja klikib nupul, akna suurus muutub vms.), käivitab brauser eelnevalt defineeritud haldaja. Nii ei pea skript lehel pidevalt töötama - lehe laadimisel tuleb vaid defineerida erinevad tegevused erinevate sündmuste jaoks ja peale seda võib skript oma töö lõpetada, kui aga määratud sündmus toimub, kutsutakse skript uuesti ellu.

Erinevus brauserite vahel DOM level 0 sündmuste haldamisel on see, et moodsad brauserid (Firefox, Opera, Chrome) annavad sündmuse haldajale kaasa parameetrina sündmuse objekti, samas kui Internet Explorer seda ei tee (IE puhul saab sama väärtuse kätte objektist window.event).

Sündmuste defineerimine

DOM level 0 sündmusi saab defineerida kahel viisil - otse HTMl koodi kirjutatuna või skriptis elemendi meetodi defineerimisel.

HTML koodis saab sündmuse haldaja defineerida tavalise tekstilise parameetrina - juhul kui brauser selle avastab teisendatakse see tekst Function funktsiooni abil funktsiooniobjektiks ja see omistatakse elemendile meetodina.

<body onload="alert('leht on laetud');">
    <a href="/" onclick="alert('vajutasid lingile')">link</a>
</body>

Elemendi meetodi defineerimine on samuti lihtne, vastavale sündmusele tuleb omistada lihtsalt funktsiooni tüüpi väärtus.

<script>
    window.onload = function(){
        alert("leht on laetud");
    }
</script>

Oma lihtsuse tõttu on DOM level 0 sündmused senini populaarsed (eriti just HTML koodis kasutatavad tekstilised defineerimised). Lihtsamate skriptide puhul on see üsnagi mõistlik, kuid vähegi keerukamate rakenduste puhul tasub kindlasti kaaluda sündmuste haldajate defineerimist juba struktureeritumal kujul, mida võimaldab DOM level 2.

Sündmuse kuulamise peatamine

Sündmuse kuulamise saab lõpetada, kui omistada sündmuse kuularile tühi väärtus.

window.onresize = null;

Sündmuse edasise tegevuse peatamine

Juhul kui sündmuse peale käivitatud skript otsustab, et seda konkreetset toimunud sündmust enam edasi rakendada ei tohi (näiteks kasutaja klikkis kustutamise lingil ning ilmunud valikudialoogist otsustas tegevuse katkestada), saab sündmuse peatada tagastades mittetõese väärtuse. Kusjuures tegu peab olema kindlasti väärtusega false, sest näiteks undefined korral, mis on samuti mitte-tõene väärtus, lõpetamise käsku ei arvestata.

<a href="kustuta.php" onclick="return confirm('Kas oled kindel?')">kustuta</a>

Näites kuvatakse kasutajale confirm dialoogiaken tekstiga „Kas oled kindel?“ ning tagastatakse selle väärtus (kui kasutaja vajutas „OK“, siis true, vastasel juhul false). Kui sündmuse haldaja tagastas väärtuse false, siis brauser lingi suunamist ei teosta.

Sisuliselt saab selle kirja panna järgmise pseudokoodiga - kui elemendil puudub vastav sündmuse haldaja või see ei tagasta väärtust false käivitab brauser vaikimisi tegevuse (näiteks teisele aadressile navigeerimine).

if(!element.handler || elemend.handler()!==false){
    run_native_action();
}

NB! Kõiki sündmusi ei saa sellisel viisil peatada - näiteks window.onload, või window.onresize, mis käivitavad sündmuse haldaja PEALE sündmuse toimumise rakendumist (akna suurus on juba muutunud, kui onresize haldaja käivitatakse), mitte ENNE seda.

Sündmuste "mullitamine"

DOM level 0 omab juba ka tuge sündmuste „mullitamise“ jaoks. See tähendab, et kui üksteise kohal asuvatele elementidele on seatud sama sündmuse haldaja (näiteks klikkimine), siis käivtatakse ükshaaval ülemise kihi elemendist alates kuni viimase kihini välja sama sündmus kõikide elementide korral.

<div onclick="alert('alumine DIV')">
    <div onclick="alert('ülemine DIV')">DIV</div>
</div>

Kui teha hiireklikk tekstil „DIV“, siis esimesena rakendub ülemise kihi hiirekliki sündmuse haldaja (teavituse aken tekstiga „ülemine DIV“) ja seejärel alumise oma (teavituse aken tekstiga „alumine DIV“).

Mullitamist on võimalik ka lõpetada, see tähendab et üks rakendunud sündmuse haldaja saab keelata kõikide järgmiste elementide sündmuste haldajate käivitumise. Tegu ei ole küll DOM level 0 võimaluse, vaid DOM level 2 võimalusega, kuid see töötab kõigis tänapäeval kasutuses olevate brauseritega.

Selle jaoks tuleb standardeid järgivates brauserites kutsuda välja sündmuse objekti meetod stopPropagation ning Internet Exploreris seada omaduse cancelBubble väärtuseks tõene väärtus (true).

<div onclick="alert('see sündmus ei rakendu kunagi')">
    <div onclick="alert('Ülemine DIV'); if(window.event)window.event.cancelBubble = true; else arguments[0].stopPropagation();">
        DIV
    </div>
</div>

Näites kontrollib ülemise kihi sündmuse haldaja kas eksisteerib objekt window.event (Internet Explorer) ja sellisel juhul seab selle omaduse cancelBubble väärtuseks true, vastasel juhul aga eeldab et funktsiooni esimeseks parameetriks on sündmuse objekt ja rakendab sellel meetodi stopPropagation.

Juhul kui klikkida tekstil „DIV“ rakendub vaid ülemise kihi sündmuse haldaja, alumise oma aga mitte kunagi, kuna ülemise kihi sündmuse haldaja keelas selle ära.

DOM level 0 plussid ja miinused

Plussid

  • Väga lihtne kasutusele võtta
  • Toetatud kõikide brauserite poolt
  • Lihtne ja üheselt mõistetav

Miinused

  • Vorm ja tegevused ei ole HTML koodis defineeritud haldajate korral eraldatud
  • Ainult kahetasemeline - skripti poolt defineeritud tase ja brauseri vaiketegevuse tase (korraga saab registreerida ühe sündmuse jaoks ainult ühe haldaja)

DOM level 2

MSIE

DOM level 3

Sündmuste haldajate optimeerimine

Kuna sündmuse haldaja seadmine on suhteliselt „kallis“ tegevus, tasub tihtipeale nende seadmistega kokku hoida ja proovida alternatiivseid võimalusi. Üheks levinuimaks optimeerimise meetodiks on ühe üldise sündmuse haldaja seadmine tervele suurele blokile. Näiteks kui mingis kindlas blokis on suur hulk erinevaid nuppe, siis ei seata sündmuse haldajaid neile igaleühele eraldi, vaid seatakse tervele blokile ning sündmuse toimudes kontrollitakse sündmuse objektis, millisele konkreetsele nupule klikiti. Nii viiakse CPU „kulu“ lehe genereerimise juurest (suure hulga sündmuste seadmine) klikkimise juurde (kontrollimine, millisele nupule klikiti).

Näide

Kui lehel asub järgmine blokk nuppudega

<div id="nuppude_blokk">
    <input type="button" value="nupp1"/>
    <input type="button" value="nupp2"/>
    <input type="button" value="nupp3"/>
</div>

Ja sellele nuppudega blokile registreerida geneeriline sündmuse haldaja

DOM level 2 toega brauserid:

document.getElementById("nuppude_blokk").addEventListener(
    "click",
    function(event){
        if(event.target.tagName=="INPUT"){
            alert(event.target.value);
        }
    },
    false
);

Internet Explorer:

document.getElementById("nuppude_blokk").attachEvent(
    "onclick",
    function(event){
        if(event.srcElement.tagName=="INPUT"){
            alert(event.srcElement.value);
        }
    }
);

saab ikkagi vajadusel teada, millisele nupule klikiti ning saab viia tegevused sellele vastavalt läbi.

Kolme jälgitava elemendi korral pole väga suurt vahet, aga kui on kasutusel näiteks juba sajad elemendid, millele oleks vaja ühtemoodi sündmuste haldajaid külge panna, muutub see brauseri jaoks juba üsnagi koormavaks - sellisel juhul olekski mõistlik kasutada näidatud geneerilisi sündmuste haldajaid, mis delegeerivad vastavalt klikitud elemendile tegevused edasi.

Selle lähenemise suureks plussiks on ka elementide sündmuste haldamise eemaldamise lihtsus - kuna ühelgi elemendil pole otseselt sündmuse haldajat registreeritud, saab neid elemente lehele lisada/eemaldada dünaamiliselt ilma et peaks mälu raiskamise pärast muretsema (juhul kui kustutada element, millel on seatud sündmus, võib see sündmus mõningatel juhtudel „õhku rippuma jääda“ tekitades sellega probleeme).