Modern technológiák 2.

2. A HTML programozás alapjai

Horváth Győző
Egyetemi adjunktus
1117 Budapest, Pázmány Péter sétány 1/c., 2.408-as szoba
Tel: (1) 372-2500/8469
horvath.gyozo@inf.elte.hu

Ismétlés

  • JavaScript nyelvi elemei
    • elemi és összetett típusok
    • vezérlési szerkezetek
    • operátorok
  • Alapvető kommunikáció
    • beolvasás (prompt, confirm)
    • kiírás (console.log, alert, document.writeln)

Felépítés

  • [✔] JavaScript nyelv
  • JavaScript és HTML kapcsolata

Egyszerű példa: Helló név!

  • Feladat
    • Bekérni a nevet, pl. "Senki bácsi"
    • Kiírni: "Hello Senki bácsi!"
  • Eddigi tudásunkkal
    • prompt és alert
var nev = prompt('Hogy hívnak?', 'Senki bácsi');
alert('Hello ' + nev + '!');

... de nem így szokták megoldani

Egyszerű példa: Helló név!

  • Űrlap
    • Gomb lenyomása
    • Érték kiolvasása
    • Eredmény megjelenítése
Név:

<form>
  Név: <input type="text"> 
  <br>
  <input type="button" value="Köszönj!">
</form>

Megoldás lépései

  1. [ ] Reagálni a gomb lenyomására.
  2. [ ] Kiolvasni a szöveges beviteli mező értékét (beolvasás).
  3. [✔] Előállítani a bemenet alapján a kimenetet, azaz az üdvözlő szöveget (feldolgozás).
  4. [ ] Megjeleníteni az üdvözlő szöveget (kiírás).

Kérdések a megoldáshoz

  • Hogyan lehet a gomb lenyomására reagálni?
  • Hogyan tudom a szöveges mező értékét kiolvasni? (valaminek a valamije)
    • JavaScriptből hogyan érem el a szöveges mezőt? (tetszőleges HTML dokumentumbeli elemre hivatkozás)
    • Ha elértem a szöveges mezőt, akkor hogyan tudom a benne lévő értéket kiolvasni? (tulajdonság)
  • Hogyan tudom az eredményt nem felugró ablakkal megjeleníteni, hanem a dokumentumban?

Elemek elérése

Dokumentum Objektum Modell (DOM)

Elemek elérése

  • Hogyan tud a JavaScript egy tetszőleges HTML elemet elérni?
  • Leíró nyelv vs Programozási nyelv → API
  • Ez nem a JavaScript nyelvben van definiálva.
  • Ezt a JavaScriptet futtató környezet biztosítja, ami most a böngésző
  • A böngésző tesz lehetővé olyan kapcsolódási pontokat (interfészeket), amelyen keresztül a HTML dokumentum JavaScripttel módosítható.

Elemek elérése

  • Kétféle interfész
    • DOM
    • (BOM)

DOM

  • A HTML dokumentum is egy fastruktúra
    • Minden elemnek legfeljebb 1 szülője van
    • Minden elemnek lehetnek gyerekei
  • Az oldal betöltésekor a böngésző minden HTML elemnek létrehoz egy objektumot.
  • Ezeket az objektumokat ugyanolyan fastruktúrába rendezi, mint az eredeti elemeket.
  • Kialakul egy objektum-hierarchia.
  • Ez a DOM.
  • A megjelenítés a DOM alapján történik.
  • Az objektumok JavaScript objektumok.

HTML mint faszerkezet

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <form id="form1">
      Név: <input type="text" name="nev" id="nev">
      <br>
      <input type="button" value="Köszönj!" name="gomb" id="nev">
    </form>
  </body>
</html>

DOM

Felület

Sematikus kapcsolatrendszer

Élő kapcsolat

Document Object Model – DOM

  • Dokumentum Objektum Modell
  • Korszerű, minden böngésző támogatja
  • Szabványos interfész fastruktúra alapú hierarchiához
    • DOM Level 1 (1998)
    • DOM Level 2 (2000)
    • DOM Level 3 (2004)
    • DOM Events Level 2 (2000)
  • Tulajdonságok, metódusok és események
  • HTML, XML

DOM műveletek

  • Rengeteg művelet (elemek, attribútumok)
    • bejárás
    • létrehozás
    • módosítás
    • törlés
  • DOM gyökere: document

Egy elem kiválasztása

  • Azonosító (id) alapján
    • document.getElementById('id')
    • a leggyorsabb
  • CSS szelektor segítségével
    • document.querySelector('szelektor')
    • a legáltalánosabb
Név: <input type="text" id="nev">
document.getElementById('nev')
document.querySelector('#nev')
document.querySelector('input[type=text]')
document.querySelector('body > form:nth-child(1) > input:nth-child(1)')

// Változóba kimentve
var nev = document.querySelector('#nev');

Több elem kiválasztása

  • név alapján
  • elemnév alapján
  • stílusosztály alapján
  • CSS szelektor segítségével
    • document.querySelectorAll('szelektor')
var inputs = document.querySelectorAll('input');
console.log(inputs);  // Tömbszerű objektum

// Iterálás
for (var i = 0; i < inputs.length; i++) {
  var input = inputs[i];
  console.log(input.innerHTML);
}

// Iterálás (ES6)
for (var input of inputs) {
  console.log(input.innerHTML);
}

Elemek elérése – összefoglalás

  • BÁRMELYIK elem elérhető JavaScriptből
  • kiválasztás CSS szelektorokkal
  • Egy elem: id-t kell adni neki
    • document.getElementById('id')
    • document.querySelector('#id')

Tulajdonságok

Attribútum-programozás

Analóg, felfedező, referencia alapú módszer

Mit tud egy DOM objektum?

  • A szabvány meghatározza, hogy egy DOM objektum mit tud
  • Objektum
    • tulajdonságok
    • metódusok
  • Minket főleg a tulajdonságok érdekelnek

Szabványos módszer

Analóg módszer

  • Elnevezési konvenció: általában minden DOM objektumnak olyan tulajdonságai vannak, amilyen attribútumai a neki megfelelő HTML elemnek.
  • Átírási szabály: camel case
    • ezEgyÖsszetettSzó
    • elsőKicsiÖsszetételnélNagyBetűk
    • pl. getElementById

Analóg módszer – input mező

HTML attribútum

  • id
  • name
  • type
  • value
  • readonly
  • maxlength

JavaScript tulajdonság

  • id
  • name
  • type
  • value
  • readOnly
  • maxLength

Felfedező módszer

  • JavaScript konzolban vizsgáljuk meg az elemet
  • DOM fül
  • Böngésző specifikus tulajdonságok is megjelenhetnek → óvatosan ezzel a módszerrel

Felfedező módszer

Példa: input mező értéke

HTML

<input type="text" name="nev" id="nev">

JavaScript

document.querySelector('#nev').value

// Például:
var nev = document.querySelector('#nev').value;

// Írható olvasható tulajdonság
document.querySelector('#nev').value = 'Győző';

Tulajdonságok - összefoglalás

  • HTML attribútumok olvasása/írása
  • Módszer
    • Funkcionalitás (pl. érték)
    • Megfelelő attribútum (pl. value)
    • Megfelelő tulajdonság (pl. value)
    • Olvasása/írása (lekérdezés/értékadás)

Eseménykezelés

Inline, tradícionális, szabványos, IE specifikus módszer

Esemény és eseménykezelő

  • Akció-reakció elve
  • Akció – kiváltó ok
    • Környezet (böngésző) eleme (pl. oldalbetöltődés)
    • Felhasználó cselekvése (pl. kattintás, egérmozgatás)
  • Reakció = események
    • HTML elemek jelzései (gomb: kattintás történt)
  • Ezekre az eseményekre lehet feliratkozni eseménykezelő függvényekkel

Események típusai

  • Egéresemények
    • click
    • dblclick
    • mouseup
    • mousedown
    • mouseover
    • mousemove
    • mouseout

Események típusai

  • Billentyűzetesemények
    • keydown
    • keyup
    • keypress
  • Oldal események
    • load (window, frame, object, image)
    • unload (window, frame)
    • abort (image, object)
    • error (object, image, frame)
    • resize (document)
    • scroll (document)

Események típusai

  • Űrlap és űrlapelem események
    • submit (form)
    • reset (form)
    • select (input, textarea)
    • change (input, select, textarea)
    • focus (input, select, textarea, label, button)
    • blur (input, select, textarea, label, button)

Események típusai

  • Érintés események
    • touchstart
    • touchend
    • touchmove
    • touchenter
    • touchleave
    • touchcancel

Eseménykezelő regisztrálása

  • Inline módszer
  • Tradícionális
  • Szabványos

Inline módszer

  • HTML attribútumként jelenik meg az eseménykezelő
  • Történetileg az első módszer
  • Mindenhol működik
<!-- Általában -->
<elem ontípus="javascript kód">

<!-- Például -->
<input type="button" id="gomb" onclick="hello()">

Tradícionális módszer

  • Programozottan rendelhető eseménykezelő egy elem eseményéhez
  • Nem szabványos, de minden böngésző támogatja
  • Egy elemhez csak egy eseménykezelő köthető
elem.ontípus = függvény;

// És NEM:
elem.ontípus = függvény();

// Törlés
elem.ontípus = null;

// Például
document.querySelector('#gomb').onclick = hello;

Szabványos módszer

  • addEventListener, removeEventListener
  • Paraméterek
    • Esemény típusa
    • Eseménykezelő függvény
    • Elkapás iránya
// Hozzáadás/regisztrálás
elem.addEventListener('típus', fuggveny, false);
// Elvétel/leiratkozás
elem.removeEventListener('típus', fuggveny, false);

// Például
var gomb = document.querySelector('#gomb');
gomb.addEventListener('click', hello, false);

Példa: gombra kattintás

<form id="form1">
  Név: <input type="text" id="nev">
  <br>
  <input type="button" value="Köszönj!" id="gomb" onclick="hello()">
</form>

<script type="text/javascript">
function hello() {
  //...
}
</script>

Kiírás a dokumentumba

innerHTML

Kiírás a dokumentumba

  • console.log nem látszik
  • alert() csúnya
  • document.writeln() lezárt dokumentumra nem működik: újat nyit
    • a dokumentum betöltése során szabad csak használni
  • ÚJ: innerHTML
    • az elemeken belüli HTML tartalom
    • írható, olvasható
elem.innerHTML = 'Tetszőleges <i>HTML</i> szöveg'; //írás
console.log(elem.innerHTML); //olvasás

innerHTML

var p = document.querySelector('p');

// Olvasás
console.log(p.innerHTML);

// Írás
p.innerHTML = 'Tetszőleges <i>HTML</i> szöveg';

Példa – innerHTML

<form id="form1">
  Név: <input type="text" id="nev">
  <br>
  <input type="button" value="Köszönj!" id="gomb" onclick="hello()">
  <br>
  <span id="kimenet"></span>
</form>
document.getElementById('kimenet').innerHTML = 'Hello világ!';

Példafeladat megoldása

Megoldás

<form id="form1">
  Név: <input type="text" id="nev"> <br>
  <input type="button" value="Köszönj!" id="gomb" onclick="hello()">
  <br>
  <span id="kimenet"></span>
</form>
<script>
function nevbolUdvozles(nev) {
  return `Hello ${nev}!`;
}
function hello() {
  //Beolvasás
  var nev = document.querySelector('#nev').value;
  //Feldolgozás
  var udvozles = nevbolUdvozles(nev);
  //Kiírás
  document.querySelector('#kimenet').innerHTML = udvozles;
}
</script>

Finomítások

$() és $$() függvény

HTML és JavaScript szétválasztása

$() és $$() függvény

  • document.querySelector()
    • hosszú, olvashatatlanná teszi a kódot
    • könnyen elgépelhető
  • $() függvény
    • document.querySelector() helyett
    • egy elem lekérdezése
  • $$() függvény
    • document.querySelectorAll() helyett
    • több elem lekérdezése
document.querySelector('#id')  --->  $('#id')

$() és $$() függvény

Csomagoló függvények:

function $(selector) {
    return document.querySelector(selector);
}

function $$(selector) {
    return document.querySelectorAll(selector);
}

Példa

<form>
  Név: <input type="text" id="nev">
  <br>
  <input type="button" value="Köszönj!" id="gomb" onclick="hello()">
  <br>
  <span id="kimenet"></span>
</form>
<script>
function $(selector) {
    return document.querySelector(selector);
}
function nevbolUdvozles(nev) {
  return `Hello ${nev}!`;
}
function hello() {
  var nev = $('#nev').value;
  var udvozles = nevbolUdvozles(nev);
  $('#kimenet').innerHTML = udvozles;
}
</script>

Szétválasztás

  • HTML – szerkezet
  • CSS – megjelenés
  • JavaScript – viselkedés

  • HTML és CSS szétválasztása
  • HTML és JavaScript szétválasztása
    • JavaScript kódot külön állományba tenni
    • HTML kódban csak hivatkozás maradhat külső állományra

Szétválasztás – 1. lépés

Függvénydefiníciók külön állományba


<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="hello.js"></script>
  </head>
  <body>
    <form>
      Név: <input type="text" id="nev">
      <br>
      <input type="button" value="Köszönj!" id="gomb" onclick="hello()">
      <br>
      <span id="kimenet"></span>
    </form>
  </body>
</html>

Szétválasztás – 2. lépés

  • Inline eseménykezelők megszüntetése
    • Programozott hozzárendelés – szabványos modell
  • Szkript a <head>-ben
    • Az elemek még nem elérhetők
    • Az oldal betöltése után kell hozzárendelni az eseménykezelőket
    • window objektum load eseménykezelő függvényben
  • Szkript a </body> előtt közvetlenül
    • minden elem elérhető
    • nincs további teendő

Szétválasztás – HTML

Szkript a </body> előtt


<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <form>
      Név: <input type="text" id="nev">
      <br>
      <input type="button" value="Köszönj!" id="gomb">
      <br>
      <span id="kimenet"></span>
    </form>
    <script src="hello.js"></script>
  </body>
</html>

Szétválasztás – JavaScript

  • </body> előtt működik
  • <head>-ben → még nem működik

//Függvénydefiníciók
function $(selector) {
    return document.querySelector(selector);
}
function nevbolUdvozles(nev) {
  return `Hello ${nev}!`;
}
function hello() {
  var nev = $('#nev').value;
  var udvozles = nevbolUdvozles(nev);
  $('#kimenet').innerHTML = udvozles;
}
//Eseménykezelők regisztrálása
$('#gomb').addEventListener('click', hello, false);

Szétválasztás – HTML

Szkript a <head>-ben


<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="hello.js"></script>
  </head>
  <body>
    <form>
      Név: <input type="text" id="nev">
      <br>
      <input type="button" value="Köszönj!" id="gomb">
      <br>
      <span id="kimenet"></span>
    </form>
  </body>
</html>

Szétválasztás – JavaScript

Szkript a <head>-ben


//Segédfüggvények
function $(selector) {
    return document.querySelector(selector);
}
//Feldolgozó függvények
function nevbolUdvozles(nev) {
  return `Hello ${nev}!`;
}
//Eseménykezelő függvények
function hello() {
    var nev = $('#nev').value;
    var udvozles = nevbolUdvozles(nev);
    $('#kimenet').innerHTML = udvozles;
}
function init() {
    //Eseménykezelők regisztrálása
    $('#gomb').addEventListener('click', hello, false);
}
window.addEventListener('load', init, false);

Elvárás

  • Külön HTML és JavaScript állomány
  • szkript a </body> előtt (progresszív betöltés)
  • $() és $$() segédfüggvények
  • Három rész
    • adatok (felületfüggetlenül)
    • eseménykezelők
    • HTML generálók

Feladatmegoldás lépései

  1. Tervezés
    • Specifikáció (adatok)
    • Felületterv
  2. Adatszerkezetek és feldolgozó függvények (felületfüggetlen)
  3. HTML-t előállító függvények
  4. Eseménykezelők kialakítása
    • Melyik elem melyik eseményére kell mit reagálni
    • Regisztrálás

Feladatmegoldás lépései

Példa: egyszerű todo lista

Felületi elemek

<!-- ... -->
<body>
    <input type="text" name="todo" id="txtTodo">
    <input type="button" value="Hozzáad" id="btnAdd">
    <ul id="ulLista"></ul>
    <script src="todo.js"></script>
</body>
<!-- ... -->

Segédfüggvények

// Segédfüggvények
function $(selector) {
    return document.querySelector(selector);
}

function $$(selector) {
    return document.querySelectorAll(selector);
}

Adatok

// Adatok
var list = [];

function addTodo(todo) {
    list.push(todo);
}

function getList() {
    return list;
}

HTML generálók

// HTML generálók
function genList(list) {
    var s = '';
    for (var todo of list) {
        s += genLi(todo);
    }
    return s;
}

function genLi(todo) {
    return `<li>${todo}</li>`;
}

Eseménykezelők (vezérlők)

// Eseménykezelők
$('#btnAdd').addEventListener('click', onButtonClick, false);

function onButtonClick(e) {
    // Beolvasás
    var todoText = $('#txtTodo').value;
    // Feldolgozás
    addTodo(todoText);
    // Kiírás
    $('#ulLista').innerHTML = genList( getList() )
    // $('#ulLista').innerHTML += genLi( todoText );
}

Egyben

// Segédfüggvények
function $(selector) {
    return document.querySelector(selector);
}

function $$(selector) {
    return document.querySelectorAll(selector);
}

/////////////////////////////////////////////////

// Eseménykezelők
$('#btnAdd').addEventListener('click', onButtonClick, false);

function onButtonClick(e) {
    // Beolvasás
    var todoText = $('#txtTodo').value;
    // Feldolgozás
    addTodo(todoText);
    // Kiírás
    $('#ulLista').innerHTML = genList( getList() )
    // $('#ulLista').innerHTML += genLi( todoText );
}

/////////////////////////////////////////////////

// Adatok
var list = [];

function addTodo(todo) {
    list.push(todo);
}

function getList() {
    return list;
}

/////////////////////////////////////////////////

// HTML generálók
function genList(list) {
    var s = '';
    for (var todo of list) {
        s += genLi(todo);
    }
    return s;
}

function genLi(todo) {
    return `<li>${todo}</li>`;
}

JavaScript fájl felépítése

Blokkok megjegyzéssel elválasztva:

  • segédfüggvények ($() és $$())
  • eseménykezelő függvények és regisztrálásuk
  • adatok és adatkezelő függvények
  • HTML-t előállító függvények

Elvárások

  • az adatokhoz (beállítás/lekérdezés) csak függvényeken keresztül férünk hozzá, direkt elérés nincs
  • a HTML-t előállító függvények minden szükséges információt paraméterként kapnak meg, és annak megfelelő HTML-t generálnak
  • az eseménykezelő olvas és ír a felhasználói felületre, és hívja az adat és HTML blokk függvényeit

Összefoglalás

  • HTML programzás = DOM programozás
  • DOM programozás
    • elemek elérése ($())
    • tulajdonságaik módosítása (attribútumprogramozás)
    • belső részének megváltoztatása (innerHTML)
  • Eseménykezelés (szabványosan, addEventListener)
  • HTML és JavaScript szétválasztása
  • JavaScript: adatok/HTML generálók/eseménykezelők