034.4 Lecke 1
Tanúsítvány: |
Web Development Essentials |
---|---|
Verzió: |
1.0 |
Témakör: |
034 JavaScript programozás |
Fejezet: |
034.4 A weboldal tartalmának és formázásának módosítása JavaScripttel |
Lecke: |
1/1 |
Bevezetés
A HTML, a CSS és a JavaScript három különböző technológia, amelyek a weben találkoznak. Ahhoz, hogy valóban dinamikus és interaktív oldalak készülhessenek, a JavaScript programozónak a HTML és a CSS komponenseit kell futásidőben kombinálnia, amit a Document Object Model (Dokumentum Objektum Modell - DOM) használata nagyban megkönnyít.
Interakció a DOM-mal
A DOM egy olyan adatszerkezet, amely a dokumentum programozási felületeként működik, ahol a dokumentum minden aspektusa a DOM csomópontjaként jelenik meg és a DOM-ban végrehajtott minden változás azonnal visszahat a dokumentumra. A DOM JavaScriptben való használatának bemutatásához mentsük el a következő HTML-kódot egy example.html
nevű fájlba:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>HTML manipuláció JavaScripttel</title>
</head>
<body>
<div class="content" id="content_first">
<p>A dinamikus tartalom kerül ide</p>
</div><!-- #content_first -->
<div class="content" id="content_second" hidden>
<p>Második szekció</p>
</div><!-- #content_second -->
</body>
</html>
A DOM csak a HTML betöltése után lesz elérhető, ezért a következő JavaScriptet az oldal törzsének végére (a lezáró </body>
tag elé) kell írni:
<script>
let body = document.getElementsByTagName("body")[0];
console.log(body.innerHTML);
</script>
A document
objektum a legfelső DOM-elem, az összes többi elem ebből ágazik le. A getElementsByTagName()
metódus a document
-től lefelé haladva felsorolja az összes olyan elemet, amely a megadott tag nevével rendelkezik. Annak ellenére, hogy a body
tag csak egyszer szerepel a dokumentumban, a getElementsByTagName()
módszer mindig a talált elemek tömbszerű gyűjteményét adja vissza, ezért a [0]
index használata az első (és egyetlen) megtalált elem visszaadására szolgál.
A HTML tartalom
Ahogy az előző példában látható, hogy a document.getElementsByTagName("body")[0]
által visszaadott DOM elemet a body
változóhoz rendeltük. A body
változót ezután az oldal body elemének manipulálására használhatjuk, mivel az összes DOM-metódust és attribútumot örökölte az adott elemtől. Például az innerHTML
tulajdonság tartalmazza a megfelelő elem belsejébe írt teljes HTML jelöléskódot, így a belső jelölés kiolvasására használható. A console.log(body.innerHTML)
hívásunk a <body></body>
belsejében lévő tartalmat írja ki a webkonzolra. A változót arra is használhatjuk, hogy helyettesítsük ezt a tartalmat, így: body.innerHTML = "<p>Tartalom törölve</p>
.
A HTML-jelölés teljes részeinek megváltoztatása helyett praktikusabb a dokumentum szerkezetét változatlanul hagyni és csak az elemeivel interakcióba lépni. Miután a dokumentumot a böngésző megjelenítette, minden eleme elérhető a DOM-módszerekkel. Lehetőség van például az összes HTML-elem felsorolására és elérésére a *
speciális sztring használatával a document
objektum getElementsByTagName()
metódusában:
let elements = document.getElementsByTagName("*");
for ( element of elements )
{
if ( element.id == "content_first" )
{
element.innerHTML = "<p>Új tartalom</p>";
}
}
Ez a kód a document
-ben található összes elemet az elements
változóba helyezi. Az elements
változó egy tömbszerű objektum, így egy for
ciklus segítségével végigmehetünk az egyes elemein. Ha a HTML-oldalon, ahol ez a kód fut, van olyan elem, amelynek id
attribútuma a content_first
érték (lásd a lecke elején bemutatott HTML-mintaoldalt), akkor az if
utasítás megfelel ennek az elemnek, és a tartalma <p>Új tartalom</p>
-ra változik. Vegyük figyelembe, hogy a HTML-elemek attribútumai a DOM-ban a JavaScript objektumtulajdonságok pont jelölésével érhetők el: ezért az element.id
a for
ciklus aktuális elemének id
attribútumára utal. A getAttribute()
módszer is használható, például mint az element.getAttribute("id")
.
Nem szükséges az összes elemen végigmenni, ha csak egy részhalmazt szeretnénk megvizsgálni. Például a document.getElementsByClassName()
módszer a megfelelő elemeket egy adott osztályra korlátozza:
let elements = document.getElementsByClassName("content");
for ( element of elements )
{
if ( element.id == "content_first" )
{
element.innerHTML = "<p>Új tartalom</p>";
}
}
A dokumentum számos elemének ciklus segítségével történő ismétlése azonban nem a legjobb stratégia, ha egy adott elemet kell megváltoztatnunk az oldalon.
Konkrét elemek kiválasztása
A JavaScript optimalizált függvényeket kínál a pontos elem kiválasztására, amelyen dolgozni szeretnénk. Az előző ciklus teljes egészében helyettesíthető a document.getElementById()
módszerrel:
let element = document.getElementById("content_first");
element.innerHTML = "<p>Új tartalom</p>";
A dokumentum minden id
attribútumának egyedinek kell lennie, ezért a document.getElementById()
módszer csak egyetlen DOM objektumot ad vissza. Még az element
változó deklarálása is elhagyható, mert a JavaScript lehetővé teszi, hogy a metódusokat közvetlenül láncoljuk:
document.getElementById("content_first").innerHTML = "<p>Új tartalom</p>";
A getElementById()
módszer a legelőnyösebb a DOM-ban lévő elemek keresésére, mivel ha komplex dokumentumokkal dolgozunk, sokkal jobb a teljesítménye, mint az iteratív módszereké. Azonban nem minden elemnek van explicit azonosítója, és a módszer null értéket ad vissza, ha nincs a megadott azonosítóval megegyező elem (ez megakadályozza a láncolt attribútumok vagy függvények használatát is, mint például a fenti példában használt innerHTML
). Ezenkívül praktikusabb, ha ID-attribútumokat csak az oldal fő összetevőihez rendelünk, majd CSS-szelektorokkal keressük meg a gyerek elemeiket.
A CSS-ről szóló korábbi leckében bemutatott szelektorok olyan mintázatok, amelyek a DOM elemeihez illeszkednek. A querySelector()
metódus a DOM fájában az első megfelelő elemet adja vissza, míg a querySelectorAll()
metódus az összes olyan elemet adja vissza, amely megfelel a megadott szelektornak.
Az előző példában a getElementById()
módszer a content_first
ID-val rendelkező elemet hívja elő. A querySelector()
metódus ugyanezt a feladatot tudja elvégezni:
document.querySelector("#content_first").innerHTML = "<p>Új tartalom</p>";
Mivel a querySelector()
módszer szelektor-szintaxist használ, a megadott azonosítónak kettőskereszttel kell kezdődnie. Ha nem talál megfelelő elemet, a querySelector()
módszer null értéket ad vissza.
Az előző példában a content_first
div teljes tartalma lecserélődik a megadott sztringre. A sztring HTML-kódot tartalmaz, ami nem tekinthető a legjobb gyakorlatnak. Óvatosnak kell lennünk, amikor JavaScript-kódhoz hard-coded (beégetett) HTML-jelölést adunk, mert az elemek követése nehézkessé válhat, ha a dokumentum teljes szerkezetének módosítására van szükség.
A szelektorok nem korlátozódnak az elem ID-ra. A belső p
elemet közvetlenül is meg lehet címezni:
document.querySelector("#content_first p").innerHTML = "Új tartalom";
A #content_first p
szelektor csak az első #content_first
div-en belüli p
elemre fog illeszkedni. Jól működik, ha az első elemet akarjuk manipulálni. Azonban az is előfordulhat, hogy a második bekezdést szeretnénk megváltoztatni:
<div class="content" id="content_first">
<p>Ne változtassuk meg ezt a bekezdést!</p>
<p>A dinamikus tartalom ide fog kerülni.</p>
</div><!-- #content_first -->
Ebben az esetben az :nth-child(2)
pszeudo-osztályt használhatjuk a második p
elemhez való megfeleltetéshez:
document.querySelector("#content_first p:nth-child(2)").innerHTML = "Új tartalom";
A p:nth-child(2)-ben lévő `2
szám a második bekezdést jelzi, amely megfeleltethető a szelektornak. A szelektorokról és használatukról bővebben a CSS-szelektorok leckében volt szó.
Munka az attribútumokkal
A JavaScriptnek a DOM-mal való interakciós képessége nem korlátozódik a tartalom manipulálására. Valójában a JavaScript legelterjedtebb használata a böngészőben a már meglévő HTML-elemek attribútumainak módosítása.
Tegyük fel, hogy az eredeti HTML példaoldalunknak most három tartalommal teli szakasza van:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>HTML manipuláció JavaScripttel</title>
</head>
<body>
<div class="content" id="content_first" hidden>
<p>Első szekció.</p>
</div><!-- #content_first -->
<div class="content" id="content_second" hidden>
<p>Második szekció.</p>
</div><!-- #content_second -->
<div class="content" id="content_third" hidden>
<p>Harmadik szekció.</p>
</div><!-- #content_third -->
</body>
</html>
Lehet, hogy egyszerre csak egyet szeretnénk láthatóvá tenni közülük, ezért van a div
címkékben a hidden
attribútum. Ez akkor lehet hasznos például, ha egy képgalériából csak egy képet szeretnénk megjeleníteni. Ahhoz, hogy az oldal betöltésekor az egyiket láthatóvá tegyük, a következő JavaScript kódot kell hozzáadni az oldalhoz:
// Melyik tartalom legyen látható
let content_visible;
switch ( Math.floor(Math.random() * 3) )
{
case 0:
content_visible = "#content_first";
break;
case 1:
content_visible = "#content_second";
break;
case 2:
content_visible = "#content_third";
break;
}
document.querySelector(content_visible).removeAttribute("hidden");
A switch
utasítás által kiértékelt kifejezés véletlenszerűen a 0, 1 vagy 2 számot adja vissza. A megfelelő ID-szelektor ezután a content_visible
változóhoz lesz rendelve, amelyet a querySelector(content_visible)
módszer használ. A láncolt removeAttribute("hidden")
hívás eltávolítja a hidden
attribútumot az elemről.
Természetesen fordítva is lehetséges: a JavaScript-program a content_visible
attribútum kivételével minden szekcióhoz hozzárendelheti a hidden
attribútumot. Ehhez végig kell iterálni az összes olyan content div elemet, amely eltér a kiválasztottól, ezt pedig a querySelectorAll()
metódus segítségével érhetjük el:
// Melyik tartalom legyen látható
let content_visible;
switch ( Math.floor(Math.random() * 3) )
{
case 0:
content_visible = "#content_first";
break;
case 1:
content_visible = "#content_second";
break;
case 2:
content_visible = "#content_third";
break;
}
// Rejtsük el az összes content divet, ami nem content_visible
for ( element of document.querySelectorAll(".content:not("+content_visible+")") )
{
// A hidden egy boolean attribútum, tehát bármilyen érték "enabled"-dé (elérhetővé) teszi
element.setAttribute("hidden", "");
}
Ha a content_visible
változó értéke #content_first
, akkor a szelektor .content:not(#content_first)
lesz, ami a content
osztályba tartozó összes elemet jelenti, kivéve a content_first
azonosítóval rendelkező elemeket. A setAttribute()
metódus a HTML-elemek attribútumait adja hozzá vagy változtatja meg. Első paramétere az attribútum neve, a második pedig az attribútum értéke.
Az elemek megjelenésének megváltoztatására azonban a CSS a megfelelő módszer. Ebben az esetben a display
CSS tulajdonságot hidden
-re állíthatjuk, majd JavaScript segítségével block
-ra módosíthatjuk:
<style>
div.content { display: none }
</style>
<div class="content" id="content_first">
<p>Első szekció.</p>
</div><!-- #content_first -->
<div class="content" id="content_second">
<p>Második szekció.</p>
</div><!-- #content_second -->
<div class="content" id="content_third">
<p>Harmadik szekció.</p>
</div><!-- #content_third -->
<script>
// Melyik tartalom legyen látható
let content_visible;
switch ( Math.floor(Math.random() * 3) )
{
case 0:
content_visible = "#content_first";
break;
case 1:
content_visible = "#content_second";
break;
case 2:
content_visible = "#content_third";
break;
}
document.querySelector(content_visible).style.display = "block";
</script>
Ugyanazok a jó gyakorlatok, amelyek a HTML-címkék és a JavaScript keverésére vonatkoznak, a CSS-re is érvényesek. Ezért nem ajánlott a CSS tulajdonságokat közvetlenül a JavaScript kódba írni, ehelyett a CSS-szabályokat a JavaScript-kódtól elkülönítve kell megírni. A vizuális stílus váltakozásának megfelelő módja, ha az elemhez egy előre definiált CSS-osztályt választunk.
Munka az osztályokkal
Az elemekhez egynél több osztály is tartozhat, ami megkönnyíti a formázások megírását, amelyeket szükség esetén hozzá lehet adni vagy el lehet távolítani. Túl sok CSS-attribútumot kimerítő lenne közvetlenül JavaScriptben módosítani, ezért létrehozhatunk egy új CSS-osztályt ezekkel az attribútumokkal, majd hozzáadhatjuk az osztályt az elemhez. A DOM-elemek rendelkeznek a classList
tulajdonsággal, amely a megfelelő elemhez rendelt osztályok megtekintésére és manipulálására használható.
Például az elem láthatóságának megváltoztatása helyett létrehozhatunk egy további CSS osztályt a tartalom
div kiemelésére:
div.content {
border: 1px solid black;
opacity: 0.25;
}
div.content.highlight {
border: 1px solid red;
opacity: 1;
}
Ez a stíluslap vékony fekete keretet és rész-átlátszóságot ad a content
osztályú elemekhez. Csak a highlight
osztállyal is rendelkező elemek lesznek teljesen átlátszatlanok és vékony piros szegélyűek. Ezután ahelyett, hogy közvetlenül módosítanánk a CSS tulajdonságokat, mint ahogy azt korábban tettük, használhatjuk a classList.add("highlight")
metódust a kiválasztott elemben:
// Melyik tartalom legyen kiemelve
let content_highlight;
switch ( Math.floor(Math.random() * 3) )
{
case 0:
content_highlight = "#content_first";
break;
case 1:
content_highlight = "#content_second";
break;
case 2:
content_highlight = "#content_third";
break;
}
// A kiválasztott div kiemelése
document.querySelector(content_highlight).classList.add("highlight");
Az eddig látott technikák és példák mindegyike az oldal betöltési folyamatának végén történt, de nem korlátozódnak erre a szakaszra. Valójában az teszi a JavaScriptet olyan hasznossá a webfejlesztők számára, hogy képes reagálni az oldalon bekövetkező eseményekre, ezt pedig a következőkben fogjuk látni.
Eseménykezelők
Minden látható oldalelem érzékeny az interaktív eseményekre, például a kattintásra vagy az egérnek a mozgatására. Ezekhez az eseményekhez egyéni műveleteket társíthatunk, ami nagyban kibővíti a HTML-dokumentumban rejlő lehetőségeket.
Valószínűleg a legnyilvánvalóbb HTML-elem, amely a kapcsolódó művelet előnyeit élvezi, a button
elem. Hogy megmutassuk, hogyan működik, adjunk hozzá három gombot a példaoldal első div
eleme fölé:
<p>
<button>Első</button>
<button>Második</button>
<button>Harmadik</button>
</p>
<div class="content" id="content_first">
<p>Első szekció.</p>
</div><!-- #content_first -->
<div class="content" id="content_second">
<p>Második szekció.</p>
</div><!-- #content_second -->
<div class="content" id="content_third">
<p>Harmadik szekció.</p>
</div><!-- #content_third -->
A gombok önmagukban nem csinálnak semmit, de tegyük fel, hogy a megnyomott gombnak megfelelő div
-t szeretnénk kiemelni. Az onClick
attribútummal minden egyes gombhoz rendelhetünk egy műveletet:
<p>
<button onClick="document.getElementById('content_first').classList.toggle('highlight')">Első</button>
<button onClick="document.getElementById('content_second').classList.toggle('highlight')">Második</button>
<button onClick="document.getElementById('content_third').classList.toggle('highlight')">Harmadik</button>
</p>
A classList.toggle()
metódus hozzáadja a megadott osztályt az elemhez, ha még nincs megadva, és eltávolítja, ha már meg van adva. Ha lefuttatjuk a példát, akkor észrevehetjük, hogy egynél több div
lehet egyszerre kiemelve. Ahhoz, hogy csak a megnyomott gombnak megfelelő div
elemet emeljük ki, el kell távolítani a többi div
elemről a highlight
osztályt. Ennek ellenére, ha az egyéni művelet túl hosszú, vagy egynél több sornyi kódot tartalmaz, praktikusabb az elem tagen kívül egy függvényt is megírni:
function highlight(id)
{
// A "highlight" osztály eltávolítása az összes content elemről
for ( element of document.querySelectorAll(".content") )
{
element.classList.remove('highlight');
}
// A "highlight" osztály hozzáadása a megfelelő elemhez
document.getElementById(id).classList.add('highlight');
}
Az előző példákhoz hasonlóan ez a függvény is elhelyezhető egy <script>
tagben vagy egy külső, a dokumentumhoz kapcsolódó JavaScript-fájlban. A highlight
függvény először eltávolítja a highlight
osztályt a content
osztályhoz tartozó összes div
elemről, majd hozzáadja a highlight
osztályt a kiválasztott elemhez. Ezt követően minden gombnak meg kell hívnia ezt a függvényt az onClick
attribútumából, a megfelelő azonosítót használva a függvény argumentumaként:
<p>
<button onClick="highlight('content_first')">Első</button>
<button onClick="highlight('content_second')">Második</button>
<button onClick="highlight('content_third')">Harmadik</button>
</p>
Az onClick
attribútumon kívül használhatjuk az onMouseOver
attribútumot (akkor aktiválódik, amikor a mutatóeszközzel a kurzort az elemre mozgatjuk), az onMouseOut
attribútumot (akkor aktiválódik, amikor a mutatóeszköz már nem az elemen belül van), stb. Az eseménykezelők ráadásul nem korlátozódnak a gombokra, így ezekhez az eseménykezelőkhöz az összes látható HTML-elem esetén rendelhetünk egyéni műveleteket.
Gyakorló feladatok
-
A
document.getElementById()
metódussal hogyan tudnánk beilleszteni a “Dinamikus tartalom” kifejezést abba az elembe, amelynek az ID-ja amessage
? -
Mi a különbség aközött, ha a
document.querySelector()
metódussal, vagy adocument.getElementById()
metódussal hivatkozunk egy elemre az ID alapján? -
Mi a célja a
classList.remove()
metódusnak? -
Mi az eredménye a
myelement.classList.toggle("active")
metódus használatának, ha amyelement
nem rendelkezik azactive
osztállyal?
Gondolkodtató feladatok
-
A
document.querySelectorAll()
módszer milyen argumentummal utánozza adocument.getElementsByTagName("input")
módszert? -
Hogyan használhatjuk a
classList
tulajdonságot egy adott elemhez tartozó összes osztály felsorolására?
Összefoglalás
Ez a lecke azt mutatja be, hogyan lehet a DOM (Document Object Model) segítségével, a JavaScriptet használva megváltoztatni a HTML-tartalmakat és azok CSS-tulajdonságait. Ezeket a változásokat felhasználói események indíthatják el, ami dinamikus felületek létrehozásához nagyon hasznos. Ez a lecke a következő fogalmakat és eljárásokat veszi át:
-
Hogyan vizsgáljuk meg a dokumentum szerkezetét az olyan metódusok segítségével, mint a
document.getElementById()
,document.getElementsByClassName()
,document.getElementsByTagName()
,document.querySelector()
és adocument.querySelectorAll()
. -
A dokumentum tartalmának módosítása az
innerHTML
tulajdonsággal. -
Hogyan adhatunk hozzá és módosíthatunk az oldalelemek attribútumain a
setAttribute()
és aremoveAttribute()
metódussal. -
Az elemek osztályainak manipulálása a
classList
tulajdonság használatával és ezen tulajdonság kapcsolata a CSS formázásokkal. -
Hogyan kössünk függvényeket bizonyos elemek egérrel kapcsolatos eseményeihez.
Válaszok a gyakorló feladatokra
-
A
document.getElementById()
metódussal hogyan tudnánk beilleszteni a “Dinamikus tartalom” kifejezést annak az elembe, amelynek az ID-ja amessage
?Az
innerHTML
tulajdonság segítségével:document.getElementById("message").innerHTML = "Dinamikus tartalom"
-
Mi a különbség aközött, ha a
document.querySelector()
metódussal, vagy adocument.getElementById()
metódussal hivatkozunk egy elemre az ID alapján?A szelektorokat használó függvényekben, mint például a
document.querySelector()
, az azonosítót kettőskereszttel kell kiegészíteni. -
Mi a célja a
classList.remove()
metódusnak?Eltávolítja az osztályt (amelynek neve a függvény argumentumaként szerepel) a megfelelő elem
class
attribútumából. -
Mi az eredménye a
myelement.classList.toggle("active")
metódus használatának, ha amyelement
nem rendelkezik azactive
osztállyal?A metódus hozzárendeli az
active
osztályt amyelement
-hez.
Válaszok a gondolkodtató feladatokra
-
A
document.querySelectorAll()
módszer milyen argumentummal utánozza adocument.getElementsByTagName("input")
módszert?A
document.querySelectorAll("input")
használata az oldal összesinput
elemére illeszkedik, akárcsak adocument.getElementsByTagName("input")
. -
Hogyan használhatjuk a
classList
tulajdonságot egy adott elemhez tartozó összes osztály felsorolására?Az
classList
tulajdonság egy tömbszerű objektum, így egyfor
ciklus segítségével végig lehet menni a benne található összes osztályon.