News & Blog

DOM 1. rész – A DOM bejárása

News & Blog

Alapok

Egy HTML oldal valamennyi eleme elérhető a DOM-ban. De mi is ez a DOM? Az elnevezés magyarul a Dokumentum Objektum Modell, míg angolul a Document Object Model szavak kezdőbetűiből alkotott mozaikszó. A DOM gyakorlatilag egy olyan platform- és nyelvfüggetlen objektummodell, mely (jelen esetben) egy HTML oldal (de lehetne XHTML, XML vagy más rokon formátumú is) valamennyi elemét elérhetővé teszi egymással gyerek-szülő kapcsolatban álló objektumok rendszereként. 

Ebben a dokumentum hierarchiában a legfelső elem maga a HTML dokumentum, melyre a document szóval hivatkozunk. Nézzük meg az alábbi igen egyszerű (gyakorlatilag üres) HTML oldalt.

<html>
	<head></head>
	<body></body>
</html>

Az ehhez az oldalhoz tartozó DOM-ot a következő ábra mutatja:

Ebben a DOM-ban első ránézésre tehát 4 objektum van (ezt azért a későbbiekben még pontosítjuk), a Document, a HTML, a HEAD és a BODY. Ezek ki is írathatók az alább kis kóddal (Az oldal meg is tekinthető a kód alatti linkre kattintva.):

<html>
<head></head>
<body>
  <script>
    alert( "Document: " + document); 
    alert( "HTML: " + document.documentElement ); 
    alert( "HEAD: " + document.head );
    alert( "BODY: " + document.body );
  </script>
</body>
</html>

KÓD

Kicsit idegesítő ezeket az alert() üzeneteket végigkattintgatni, ezért a továbbiakban a különböző kimeneteket összegyűjtjük egy string-be, és azt írjuk ki egyetlen alert() üzenettel:

<html>
<head></head>
<body>
  <script>
	let str="Document: " + document; 
    str+="\nHTML: " + document.documentElement ; 
    str+="\nHEAD: " + document.head ;
    str+="\nBODY: " + document.body ;
	alert(str);  
  </script>
</body>
</html>

KÓD

Elhiszem, hogy az előző kód olvashatóbb volt, de érdemes bevállalni ezt a kicsit bonyolult szintaxist, az olvashatóbb kimenet kedvéért. (Később pedig már meg sem kottyan az ilyen bonyolultságú kód.) Létrehozunk egy str nevű változót (a let-tel a láthatóságát adjuk meg, majd később beszélünk róla), kezdőértékéül adjuk az első alert() üzenetét, utána pedig hozzáfűzzük a többiét. (Az str+= kód az str=str+ kóddal egyenértékű, a “\n” pedig a soremelés.) A végén pedig megjelenítjük egyetlen alert()-ben az str tartalmát. (Ahol persze egyetlen üzenetet jelenít meg az alert(), ott nem bonyolítjuk ezzel a kódot.)

Folytassuk tovább a HTML kódunk DOM szerkezetének elemzését.

A böngésző a HTML oldalt soronként olvassa, és mindig amikor elér egy elemet, létrehozza a hozzá tartozó objektumot. Ügyeljünk arra, hogy addig nem hivatkozhatunk egy elemre, amíg a hozzá tartozó objektum nem jött létre. Például a <head> részben nem hivatkozhatunk a <body> elemre, hiszen a <head> részben még nincsen információ a <body>-ról.

<html>
<head>
  <script>
	   alert( "BODY: " + document.body );
  </script>
</head>
<body></body>
</html>

D

A nagy család

A DOM hierarchiájában az egyes objektumok egymáshoz való viszonyát rokoni kapcsolatokkal írjuk le. Vannak szülő, gyermek, testvér objektumok. Értelmezhető az első és utolsó gyermek, valamint az előző és a következő testvér viszony is. Ha visszatekintünk az első ábrára, akkor a document objektumnak az első (és egyben utolsó) gyermeke a <html> objektum, mely a <head> és a <body> szülő objektuma, míg a <html> objektumnak a <head> és a <body> a gyermekei, mégpedig a <head> az első gyermeke, míg a <body> az utolsó. A <head> és a <body> egymás testvérei. A <body> szemszögéből a <head> az előző testvér, míg a <head> szemszögéből a <body> a következő testvér. (Tekintsünk most el attól, hogy például a <head> igazából a HTML oldal egy eleme (tag-je), míg a hozzá tartozó objektum a HTMLHeadElement, így ha igazán korrektül szeretnénk leírni az objektumok egymáshoz való viszonyát, akkor azt kellene mondanunk, hogy a HTMHeadElement testvére a HTMLBodyElement. Az olvashatóság kedvéért inkább a tag-ek elnevezését használjuk.)

A rokonsági kapcsolatokkal rendelkező objektumokat különböző tulajdonságokon keresztül érhetjük el. Valakinek az első gyermekét a firstChild, az utolsó gyermekét a lastChild, az előző testvérét a previousSibling vagy a previousElementSibling, a következő testvérét a nextSibling vagy a nextElementSibling (a közöttük lévő különbséget később még tisztázzuk),míg a szülőjét a parentNode vagy parentElementNode tulajdonság tárolja. Játszunk el azzal, hogy kiíratjuk az egyes objektumok rokonait. Az alábbi kód például a <body> objektumát éri el különböző módokon:

<html>
<head></head>
<body>
  <script>
    str="BODY: " + document.firstChild.lastChild;
    str+="\nBODY: " + document.firstChild.firstChild.nextElementSibling;    
    str+="\nBODY: " + document.firstChild.firstChild.nextSibling.nextSibling;    	
    str+="\nBODY: " + document.documentElement.firstChild.nextElementSibling;  
    alert(str);     
  </script>
</body>
</html>

KÓD

  • Az első esetben a document első gyermeke a <html>, és a <html> utolsó gyermeke a <body>.
  • A második esetben a document első gyermeke a <html>, annak első gyermeke a <head>, melynek következő testvére a <body>.
  • A harmadik esetben a document objektum documentElement tulajdonsága a <html>-t adja vissza, mely első elemének (a <head>-nek) következő testvére a <body>.

De mi van akkor, ha egy szülő valamennyi gyermekét el akarjuk érni? Ehhez használhatjuk a childNodes tulajdonságot, mely egy gyűjteményben tárolja a szülőhöz tartozó valamennyi gyermeket. (Legyen most elég, hogy a gyűjtemény hasonlít a tömbre, indexelve érhetjük el az elemeit, de tömbmetódusok nem érhetők el rajta.) Próbáljuk meg kiíratni most ennek segítségével <html> gyermekeit:

<html>
<head></head>
<body>
  <script>
    let str="HEAD: " + document.documentElement.childNodes[0];
    str+="\nMi ez?: " + document.documentElement.childNodes[1];
    alert(str);
  </script>
</body>
</html>

D

Meglepődve tapasztalhatjuk, hogy míg a 0. eleme az elvárt <head>, addig az 1. elemre valamilyen szöveg típusú objektumot kapunk vissza a <body> helyett.

Jelenítsük meg a tömb 3. elemét is (a 2. indexűt), így már elérhetjük a <body> elemet is. 

<html>
<head></head>
<body>
  <script>
    let str="HEAD: " + document.documentElement.childNodes[0];
    str+="\nENTER: " + document.documentElement.childNodes[1];
    str+="\nBODY: " + document.documentElement.childNodes[2];
    alert(str);
  </script>
</body>
</html>

KÓD

Mi ez a titokzatos szöveg típusú objektum a DOM-ban? A sorvégi ENTER. Ahhoz, hogy ezt világosan megértsük, meg kell először ismernünk a különböző csomópont (node) típusokat. Az előző példákban a következő csomópontokat használtuk a DOM-ban: document, html, head és body. Ezeket nevezzük elem csomópontoknak. A DOM-ban viszont számos más csomóponttípus is létezik, nézzük meg ezeket:

  • az egész dokumentumot reprezentálja egy document csomópont
  • a dokumentumon belül minden HTML elem egy elem csomópont
  • egy HTML elemen belüli szöveg egy szöveg csomópont
  • minden HTML attribútum egy attribútum csomópont
  • a HTML megjegyzések egy-egy komment csomópont-nak felelnek meg

Ahogyan láttuk, minden csomópontnak egyetlen szülője lehet (kivéve a document-nek, neki nincsen), és egy csomópontnak több gyermeke is lehet, a testvérek szülője pedig értelemszerűen ugyanaz.

Egy csomópont típusát a nodeType tulajdonsága adja vissza.  Nézzünk a legfontosabbakra egy-egy példát. Induljunk ki az alábbi HTML kódból:

<!DOCTYPE html>
<html>
<head></head>
<body>
	<h1 class="cimek">IKTBlog</h1> <!-- Ez egy megjegyzés -->
</body>
</html>

A különböző csomópont típusok ebben a kódban 6-ot találunk meg (Összesen 12 csomóponttípust definiál a DOM.):

csomópont típusának nevepéldacsomóponttípustípuskód
document csomópontdocumentDOCUMENT_NODE9
elem csomópont<h1 class=”cimek”>IKTBlog</h1>ELEMENT_NODE1
szöveg csomópontIKTBlogTEXT_NODE3
attribútum csomópontclass=”cimek”ATTRIBUTE_NODE*2
megjegyzés csomópont<!– Ez egy megjegyzés –>COMMENT_NODE8
dokumentum típus csomópont<!DOCTYPE html>DOCUMENT_TYPE_NODE10

* A HTML DOM-ban az attribútum típusú csomópont visszavonásra került, de attól még megtalálható.

Vegyük észre, hogy a Document nem elem típusú, vagyis az első elem típusú csomópont a <html>, ezért tekintjük a <html> elemet az összes többi elem (csomópont) gyökerének.

Nézzünk meg egy egyszerű weboldalt, és azonosítsuk benne a különböző típusú csomópontokat:

<html>
	<head>
		<style>
			#fo{border:1px green solid; width:300px; padding:10px}
			#novenyek{background-color: yellow;}
			#gyumolcsok{background-color: lightgreen;}
			.lista{background-color: lightblue;}	
		</style>
	</head>
	<body>
		<div id="fo">
			<h1 id="novenyek">Növények</h1>
			<h2 id="gyumolcsok">Gyümölcsök</h2>
			<ol>
				<li class="lista">Alma</li>
				<li class="lista">Cseresznye</li>
				<li class="lista">Barack</li>
			</ol>
		</div>
	</body>
</html>

Csak a <body> ág (részleges) DOM struktúráját a következő ábra mutatja:

Az, hogy miért részleges (vagyis nem mindent tartalmaz), a későbbiekben kerül bemutatásra. A HTML kód és a kép alapján könnyen beazonosíthatók az egyes csomópontok típusa és egymáshoz való viszonyuk. Jól látszik, hogy a <li> elemek egymás testvérei, szüőjük az <ol>. A <li> elemek ezen felül még leszármazottai a <div> elemnek is (a gyermek gyermekei…).

A csomópontok neve a nodeName tulajdonságon, míg az értékük a nodeValue tulajdonságon keresztül érhető el. Egy csomópont neve elem csomópontnál a HTML tag neve, míg attribútum csomópontnál az attribútum neve. (Document és szöveg csomópont esetén a név #document és #text.) A csomópont értéke szöveg típusú csomópontnál maga a szöveg, míg attribútum típusúnál az attribútum értéke. (Elem típus esetén nincsen definiálva, vagyis ekkor undefined.)

Az alábbi kód a saját HTML oldalán a <body> elemének gyermek objektumainak nevét írja ki. Ehhez gyakorlatilag egy for ciklussal végigfutunk a <body> gyermekobjektumait tartalmazó gyűjteményen, és minden elemének kiírjuk a nodeName tulajdonságát. Az, hogy a for ciklus meddig fusson (vagyis hány gyermek objektuma van a <body> elemnek, a childNodes length tulajdonsága adja meg.

<!DOCTYPE html>
<html>
<head></head>
<body>
    <h1 class="cimek">IKTBlog</h1><!-- Ez egy megjegyzés -->
    <script>
        let str="";
        for (let i = 0; i < document.body.childNodes.length; i++) {
            str+=document.body.childNodes[i].nodeName+"\n";
        }
        alert(str);
    </script>
</body>
</html>

D

Mivel a childNodes egy objektumgyűjtemény, alkalmazható rá a for..of szerkezet, amivel leegyszerűsíthetjük a kódot, mivel nem kell foglalkoznunk a csomópontok számával és indexelésével. A for..of szerkezet a gyűjteményből kiemeli sorban az objektumokat, így a ciklus magjában már csak a kiemelt objektumra kell hivatkoznunk:

<!DOCTYPE html>
<html>
<head></head>
<body>
<h1 class="cimek">IKTBlog</h1><!-- Ez egy megjegyzés -->
<script>
    let str="";
    for (let elem of document.body.childNodes) {
        str+=elem.nodeName+"\n";
    }
    alert(str);
</script>
</body>
</html>

D

Ha valaki mindenáron tömbként szeretné használni a gyűjteményt, van rá lehetőség, hogy átalakítsa azt egy tömbbé. (Mi ezzel itt most nem foglalkozunk.)

Felvetődhet a kérdés, hogy mi az a sok #text objektum? Hát a soremelések és szóköz, amit elhelyeztünk az oldalon. Ha kihagyjuk azokat (vagyis gyakorlatilag mindent egy sorba írunk), akkor máris eltűnnek ezek az objektumok, de akkor a kód olvashatósága jelentősen romlik. (Emiatt volt korábban az írva, hogy csak a részleges DOM struktúrát jelenítette meg az ábra.)

Amennyiben egy tetszőleges HTML oldal DOM szerkezetét szeretnénk megjeleníteni, látogassunk el a https://software.hixie.ch/utilities/js/live-dom-viewer/ oldalra, írjuk be az oldal kódját, és máris láthatjuk. Bátran kísérletezzünk rajta!

Korábban ígértem, hogy leírom a previousSibling és a previousElementSibling, valamint a netxSibling és a nextElementSibling tulajdonságok közötti különbséget. A previousSibling és a nextSibling az előző illetve a következő testvérobjektumra mutat, legyen az bármilyen típusú. A previousElementSibling és a nextElemetSibling tulajdonságokkal viszont csak az elem csomópontokon lépkedünk végig, vagyis gyakorlatilag a HTML oldalt felépítő tag-eken.

Futtassuk le az alábbi  kódot:

<!DOCTYPE html>
<html>
<head></head>
<body>
<h1 class="cimek">IKTBlog</h1><!-- Ez egy megjegyzés -->
<script>
    let str="";
    let elem=document.body.firstChild;
    while(elem){
        str+=elem.nodeName+"\n";
        elem=elem.nextSibling;
    }
    alert(str);	
</script>
</body>
</html>

D

Azt az eredményt kapjuk, mint az előző esetben, vagyis a <body> elem objektumának valamennyi gyermekét.

Megváltozik a helyzet, ha a firstChild helyet a firstElementChild, és a nextSIbling tulajdonság helyett a nextElementSibling tulajdonságot használjuk. Ilyenkor már csak a tag-eken lépkedünk végig (a <h1> és a <script> tag-en): 

<!DOCTYPE html>
<html>
<head></head>
<body>
<h1 class="cimek">IKTBlog</h1><!-- Ez egy megjegyzés -->
<script>
    let str="";
    let elem=document.body.firstElementChild;
    while(elem){
        str+=elem.nodeName+"\n";
        elem=elem.nextElementSibling;
    }
    alert(str);
</script>
</body>
</html>

D

Hasonló a különbség a parentNode és a parentElementNode között, vagyis az előző a szülő csomópontot adja vissza (legyen az bármilyen típusú), míg az utóbbi az elem típusú szülő csomópontot tárolja. Arra is van lehetőség, hogy eleve már csak az elem típusú csomópontokkal foglalkozzunk, ilyenkor a childNodes helyett a children tulajdonságt kell használnunk, mely egy olyan gyűjteményt ad vissza, melyben az elem típusú csomópontok vannak:

<!DOCTYPE html>
<html>
<head></head>
<body>
<h1 class="cimek">IKTBlog</h1><!-- Ez egy megjegyzés -->
<script>
    let str="";
    for (let elem of document.body.children) {
        str+=elem.nodeName+"\n";
    }
    alert(str);
</script>
</body>
</html>

D

Jegyezzük meg, hogy ez az objektumgyűjtemény (és a teljes DOM) csak olvasható, tehát egyszerű értékadással nem tudunk például egy <h1> elemet <h2> elemmel felülírni. Ez nem azt jelenti, hogy nem lehet a <h1>-et lecserélni egy <h2>-re, vagy akár kitörölni, de ahhoz már más módszereket kell alkalmaznunk.

Adott elemek megkeresése a DOM-ban

Mi a helyzet akkor, ha csak bizonyos elemekre van szükség a DOM-ban? Például valamilyen oknál fogva az összes <p> tag-re vagyunk kíváncsiak? Nem kell mást tennünk, mint miközben végiglépkedünk az egyes elemeken, vizsgáljuk, hogy vajon <p> tag, vagy nem.

<!DOCTYPE html>
<html>
<head></head>
<body>
    <p>Első bekezdés</p>
    <h1 class="cimek">IKTBlog</h1><!-- Ez egy megjegyzés -->
    <p>Második bekezdés</p>
    <script>
        let str="";
        for (let elem of document.body.children) {
            if(elem.nodeName=="P")
                str+=elem.nodeName+"\n";
        }
        alert(str);
    </script>
</body>
</html>

D

Ha a <p> tag tartalmára vagyunk kíváncsiak, használjuk az innerHTML tulajdonságot.

<!DOCTYPE html>
<html>
<head></head>
<body>
    <p>Első bekezdés</p>
    <h1 class="cimek">IKTBlog</h1><!-- Ez egy megjegyzés -->
    <p>Második bekezdés</p>
    <script>
        let str="";
        for (let elem of document.body.children) {
            if(elem.nodeName=="P")
            str+=elem.innerHTML+"\n";
        }
        alert(str);
    </script>
</body>
</html>

D

Egyes elemek elérése a DOM-ban

Az már remélhetőleg világos, hogyan kell a DOM-on végiglépkednünk, de ha csupán egy meghatározott elemre van szükségünk, akkor az eddig megismert módszerekkel nem jutunk célba. Mi van akkor, ha nekünk csak a 2. <p> tag tartalmára van szükségünk? Mondhatjuk azt, hogy akkor indexelve elérjük, de így a programba bedrótozzuk a helyét, vagyis a HTML oldalunk felépítésétől függne a kód működése. Szerencsére lehetőség van az egyes elemek azonosítására az id attribútum használatával. Az így azonosított elemet pedig a document objektum getElementById() metódusával tudjuk elérni. Az alábbi példában azonosítókat rendelünk a <p> tag-ekhez (elso és masodik), majd a másodikat választjuk ki a metódus segítségével. A következő példákban már olyan műveleteket fogunk elvégezni a DOM-oon belül, hogy szükség lesz az elemek változókban való tárolására, így tegyük ezt most is:

<!DOCTYPE html>
<html>
<head></head>
<body>
    <p id="elso">Első bekezdés</p>
    <h1 class="cimek">IKTBlog</h1><!-- Ez egy megjegyzés -->
    <p id="masodik">Második bekezdés</p>
    <script>
        var p=document.getElementById("masodik");
    alert( p.innerHTML );
    </script>
</body>
</html>

D

Elemcsoportok elérése a DOM-ban

Mi van akkor, ha nem adott azonosítójú, hanem valamilyen szempontból összetartozó elemeket szeretnénk elérni a DOM-ban? Ilyenkor ezeket az elemeket valamilyen közös tulajdonsággal kell ellátni, és ez alapján lehet kiválasztani. Az egyik ilyen tulajdonság lehet például az elemek neve, amelyet a name attribútummal adhatunk meg. Az azonos nevű elemeket pedig a document objektum getElemenetsByName() metódusával érhetjük el. Vigyázzunk, hogy ilyenkor egy objektum gyűjteményt kapunk vissza (akkor is, ha egyetlen elem illeszkedik erre a névre), vagyis úgy kell kezelnünk azt, mint például a childNodes gyűjteményt.

A következő példában adjunk azonos nevet a két bekezdésnek:

<!DOCTYPE html>
<html>
<head></head>
<body>
<p name="info" id="elso">Első bekezdés</p>
<h1 class="cimek">IKTBlog</h1><!-- Ez egy megjegyzés -->
<p name="info" id="masodik">Második bekezdés</p>
<script>
    let str="";
    let info=document.getElementsByName("info")
    for (let elem of info )
        str+=elem.innerHTML+"\n";
    alert(str);
</script>
</body>
</html>

D

Lehetőségünk lenne a tag-ek neve (Nem name attribútuma, hanem a tag elnevezése) alapján is elérni a bekezdéseket, ilyenkor a getElementsByTagName() metódust kell használnunk. Az alábbi kód a <p> tag-eken lépked végig:

<!DOCTYPE html>
<html>
<head></head>
<body>
<p name="info" id="elso">Első bekezdés</p>
<h1 class="cimek">IKTBlog</h1><!-- Ez egy megjegyzés -->
<p name="info" id="masodik">Második bekezdés</p>
<script>
    let str="";
    let bekezdesek=document.getElementsByTagName("P")
    for (let elem of bekezdesek )
        str+=elem.innerHTML+"\n";
    alert(str);
</script>
</body>
</html>

D

Mivel az egy csoportba tartozó elemek általában a megjelenítésükben is tartalmaznak közös szempontokat, ezért hozzájuk azonos CSS osztályt szoktunk rendelni. Így természetesen arra is van lehetőség a getElementsByClassName() metódussal, hogy az ilyen közös CSS osztályba tartozó elemeket is lekérdezzük. Módosítsuk úgy az előző példát, hogy a bekezdésekhez az info CSS osztályt rendeljük, majd válogassuk le az ilyen CSS osztállyal rendelkező <tag>-eket: 

<!DOCTYPE html>
<html>
<head></head>
<body>
<p class="info" id="elso">Első bekezdés</p>
<h1 class="cimek">IKTBlog</h1><!-- Ez egy megjegyzés -->
<p class="info" id="masodik">Második bekezdés</p>
<script>
    let str="";
    let info=document.getElementsByClassName("info")
    for (let elem of info )
        str+=elem.innerHTML+"\n";
    alert(str);
</script>
</body>
</html>

D

Ha már a CSS az azonosítón és az osztályon kívül számos más szelektorral is rendelkezik, joggal várhatjuk el, hogy ezek is rendelkezésre álljanak a DOM-ból való elem-választáshoz. Természetesen rendelkezésre állnak, a querySelector() az első olyan elemet adja vissza, amelyre illeszkedik a metódusnak paraméterként átadott szelektor, míg a querySelectorAll() az összeset. Az alábbi példában minden olyan <h1> elemet kiírunk, amely közvetlenül <p> elem után áll. (Csak az elsőt írja ki, hiszen a második <h1> előtt nem <p> hanem <h1> áll. Szúrjunk be egy <p> tag-et a második <h1> elé, akkor már az is megjelenik az eredményben.)

<!DOCTYPE html>
<html>
<head></head>
<body>
<p class="info" id="elso">Első bekezdés</p>
<h1 class="cimek">IKTBlog 1. cím</h1>
<h1 class="cimek">IKTBlog 2. cím</h1>
<p class="info" id="masodik">Második bekezdés</p>
<script>
    let str="";
    let cimek=document.querySelectorAll("p + h1")
    for (let elem of cimek )
        str+=elem.innerHTML+"\n";
    alert(str);
</script>
</body>
</html>

D

Nézzünk meg még egy példát a szelektorra. A * szelektor minden elemre illeszkedik, vagyis ezzel az oldal valamennyi elemét ki tudjuk gyűjteni:

<!DOCTYPE html>
<html>
<head></head>
<body>
<p class="info" id="elso">Első bekezdés</p>
<h1 class="cimek">IKTBlog 1. cím</h1>
<h1 class="cimek">IKTBlog 2. cím</h1>
<p class="info" id="masodik">Második bekezdés</p>
<script>
    let str="";
    let cimek=document.querySelectorAll("*")
    for (let elem of cimek )
        str+=elem.tagName+"\n";
    alert(str);
</script>
</body>
</html>

D

Az elemek tulajdonságai

Többé-kevésbé már láthatjuk, hogyan is lépkedhetünk végig különböző szempontok alapján kiválogatott elemeken, és hogyan érjük el (egyszerű esetben) a tartalmukat az innerHTML tulajdonsággal. Az elemeknek viszont lehetnek attribútumai, amelyeket szintén el szeretnénk érni. Ehhez az elem attributes tulajdonságát használhatjuk, mely az elem attribútumait tárolja. Nézzünk erre egy példát. Adott egy űrlap, amelyben van néhány beviteléi elem a maguk attribútumaival. Válasszuk ki az első elemet, és jelenítsük meg az attribútumainak a számát a length tulajdonsággal.

<!DOCTYPE html>
<html>
<head></head>
<body>
<form>
    <input type="text" name="nev" class="kotelezo" />
    <input type="text" name="cim" class="kotelezo" />
    <input type="text" name="telefon" />
    <input type="text" name="szuldatum" />
    <input type="submit" name="ok" value="ok">
</form>
<script>
    var mezo=document.body.children[0][0];   // 0. gyermek a <form>, annak 0. gyermeke a nev nevű <input> tag
    alert (mezo.attributes.length);          // Ennyi attribútuma van
</script>
</body>
</html>

D

Lépegessünk végig ezeken a tulajdonságokon, és írjuk ki a nevüket és értéküket. Egy attribútum nevét a name tulajdonság, míg értékét  a value tulajdonság tartalmazza.

<!DOCTYPE html>
<html>
<head></head>
<body>
<form>
    <input type="text" name="nev" class="kotelezo" />
    <input type="text" name="cim" class="kotelezo" />
    <input type="text" name="telefon" />
    <input type="text" name="szuldatum" />
    <input type="submit" name="ok" value="ok">
</form>
<script>
    let str="";
    let mezo=document.body.children[0][0];
    for(let tul of mezo.attributes)
        str+=tul.name+": "+tul.value+"\n";
    alert(str);
</script>
</body>
</html>

Jegyezzük meg tehát, hogy egy elem (tag) nevét a TagName, és esetleges tartalmát az innerHTML tulajdonság tartalmazza, míg attribútumok esetén a nevet a name, az értéket pedig a value tulajdonság tartalmazza.

D

Egy (a későbbiekben) hasznos példa

Az előző űrlapon a kötelezően kitöltendő mezőkhöz a “kotelezo” CSS osztályt rendeltük. Jelenítsük meg ezeket a mezőket egy figyelmeztető üzenetben. Az eddigiek alapján remélhetőleg érthető már a kód.

<!DOCTYPE html>
<html>
<head></head>
<body>
<form>
    <input type="text" name="nev" class="kotelezo" />
    <input type="text" name="cim" class="kotelezo" />
    <input type="text" name="telefon" />
    <input type="text" name="szuldatum" />
    <input type="submit" name="ok" value="ok">
</form>
<script>
    let str="";
    for(let mezo of document.getElementsByClassName("kotelezo"))
        str+="A "+mezo.attributes[1].value+" mező kitöltése kötelező!\n";
    alert(str);
</script>
</body>
</html>

D

Attól eltekintve, hogy a gyakorlatban ez a megoldás nem túl szép, a kód nagyon szépen mutatja, hogyan lehet végigseperni megadott elemeken. Van azonban a megoldásban egy nagy következetlenség. Beledrótoztuk a kódba, hogy a kötelezőséget leíró tulajdonság mindig a 1-es indexű helyen van. Ezt viszont szinte biztos, hogy a kód továbbírása során meg fogjuk sérteni például új attribútumok felvételével, beszúrásával. (Próbáljuk ki, hogy felcseréljük az egyik kötelező mezőben a name és a class attribútumok helyét.) Írjuk át a kódot, hogy ne függjön a name attribútum helyétől. Ehhez felhasználjuk a getAttribute() metódust, amely egy megadott nevű attribútum értékével tér vissza.

<!DOCTYPE html>
<html>
<head></head>
<body>
<form>
    <input type="text" name="nev" class="kotelezo" />
    <input type="text" name="cim" class="kotelezo" />
    <input type="text" name="telefon" />
    <input type="text" name="szuldatum" />
    <input type="submit" name="ok" value="ok">
</form>
<script>
    let str="";
    for(let mezo of document.getElementsByClassName("kotelezo")){
        let nev=mezo.getAttribute("name");
        str+="A "+nev+" mező kitöltése kötelező!\n";
    }
    alert(str);
</script>
</body>
</html>

D

Elemek kiválasztása saját tulajdonságok alapján

Az egyes HTML elemeknél nem csak a szabványban definiált tulajdonságokat tudjuk használni, hanem saját magunk is létrehozhatunk újakat. Ha például egy játékban számolni kell, hogy mely elemekre hányszor kattintottunk, akkor ezt úgy is meg tudjuk oldani, hogy az egyes elemekben vesszük fel ezt a számlálót. Az alábbi példában van 4 <div> elemünk (az egyszerűség kedvéért most csak egy-egy betűt tartalmaznak, de egy egyszerű stílussal különböző színű négyzeteket varázsolhatunk belőlük), mindegyikben egy számláló, amelyben számoljuk, hányszor kattintottak az elemre (most ezt konstansra állítjuk be, később megírjuk majd ezt a kattintgatást is). Jelenítsük meg, mely elemekre kattintottunk már egy tucatszor.

<!DOCTYPE html>
<html>
<head></head>
<body>
    <div id="a1" class="cella" click="12">A</div>
    <div id="a2" class="cella" click="10">B</div>
    <div id="a3" class="cella" click="8">C</div>
    <div id="a4" class="cella" click="12">D</div>
<script>
    let str="";
    for(let cella of document.getElementsByClassName("cella")){
        var click=cella.getAttribute("click");
        if(click==12)
            str+=cella.getAttribute("id")+"\n";
    }
    alert(str);
</script>
</body>
</html>

D

Ezt a kódot egy kicsit egyszerűbben is le tudjuk írni a korábban már bemutatott querySelectorAll() metódus használatával, melynek segítségével közvetlenül ki tudjuk válogatni azokat az elemeket, amelyekben egy adott attribútum meghatározott értékű:

<!DOCTYPE html>
<html>
<head></head>
<body>
    <div id="a1" class="cella" click="12">A</div>
    <div id="a2" class="cella" click="10">B</div>
    <div id="a3" class="cella" click="8">C</div>
    <div id="a4" class="cella" click="12">D</div>
<script>
    let str="";
    let cellak=document.querySelectorAll('[click="12"]');
    for(let cella of cellak){
        str+=cella.getAttribute("id")+"\n";
    }
    alert(str);
</script>
</body>
</html>

D

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük