Web-fejlesztés 2.

Elemek létrehozása, az eseménykezelés részletei

Visnovitz Márton
egyetemi tanársegéd
visnovitz.marton@inf.elte.hu

@elte-fi/courses-tt-webprog

Ismétlés

Ismétlés

  • JavaScript nyelvi alapok
  • Programozott grafika (rajz, animáció, játék)
  • HTML elemek programozása
  • Kitekintés a szerveroldali programozás világába

Ismétlés - Felületi elemek programozása

  • HTML elemek belső ábrázolása (DOM)
  • Programozási interfész (API)
  • Bemeneti-kimeneti interfész
  • elem.innerHTML, elem.innerText, elem.value

Ismétlés – DOM

  • Elemek kiválasztása
    • document.querySelector("css selector")
    • document.querySelectorAll("css selector")
  • Elem (JavaScript objektum) tulajdonságai
    • Analógia: Webfejlesztés → Webprogramozás
    • Írás/olvasás
    • Tulajdonságok (pl. innerHTML)
  • Eseménykezelés
    • Eseménytípusok
    • elem.addEventListener(type, handler)

Ismétlés - DOM

<form>
  Name: <input type="text" id="name"> <br>
  <input type="button" value="Say hello!" id="hello">
  <br>
  <span id="output"></span>
</form>
function greet(name) {
  return `Hello ${name}!`;
}

const input = document.querySelector("#name");
const output = document.querySelector("#output");
const hello = document.querySelector("#hello");

function handleHelloClick() {
  const name = input.value;
  const greeting = greet(name);
  output.innerHTML = greeting;
}

hello.addEventListener("click", handleHelloClick);

Elemek létrehozása

Dinamikusan generált felhasználói felület

Új elemek létrehozása

  • A kiírás egy speciális formája
  • A HTML kód szövegesen
  • innerHTML tulajdonság írása
  • Akár egyszerre több elemet is
<div id="output"></div>
<script>
  const greeting = "<h1>Hello <em>World</em></h1>";
  const output = document.querySelector("#output");
  output.innerHTML = greeting;
</script>

HTML generálás

// Rövid statikus szöveg megadása
const html1 = `<h1>Hello there!</h1>`;
// Többsoros statikus szöveg megadása
const html2 = `
  <div>
    <p>No, <strong>I</strong> am your father!</p>
  </div>
`;
// Változók behelyettesítése
const callsign = 'Red 5';
const html3 = `${callsign}, standing by.`;
// Tömbök kiírása leképezéssel
const callsigns = ["Red 10", "Red 7", "Red 3", "Red 6", "Red 9"];
const html4 = `
  <p>All wings, report in.</p>
  <ul>
    ${callsigns.map(callsign => `
      <li>${callsign}, standing by.</li>
    `).join("")}
  </ul>
`;
// Feltételes kiírás (elágazás)
const chanceOfSuccess = 0.4;
const html5 = `
  <span>
    I have a 
    ${chanceOfSuccess < 0.5 ? "bad" : "good"}
    feeling about this.
  </span>
`;
// Függvényekkel
function hanDescription(properties) {
  return `
    You
    <ul>
      ${properties.map(hanProperty).join("")}
    </ul>
    Nerf Herder!
  `;
}

function hanProperty(property) {
  return `<li>${property}</li>`;
}

const hanProperties = [
  "stuck up",
  "half witted",
  "scruffy looking"
];
const html6 = hanDescription(hanProperties);

Új elemek létrehozása

Programozottan:

  • Létrehozás:
    • document.createElement(elementName)
  • Beszúrás:
    • parent.appendChild(childElement)
      szülő gyerekeihez utolsóként hozzáadja az új elemet
    • parent.insertBefore(newChildElement, ref)
      referencia elé beszúrja az új elemet
    • ref.insertAdjacentElement(position, newElement)
      egy adott elemhez képes szúr be új elemet

Új elemek beszúrása

<body>
  <ul>
    <li>First</li>
    <li>Second</li>
    ✒> <✒    
    <li>Third</li>
  </ul>
  ✒> <✒    
</body>
const p = document.createElement("p");
document.body.appendChild(p);

const newLi = document.createElement("li");
const ul = document.querySelector("ul");
const refLi = 
  ul.querySelector("li:nth-of-type(3)");
ul.insertBefore(newLi, refLi);

Stílusattribútumok programozása

Ismétlés

<div class="rodian bounty-hunter" style="bottom: 72in">
  Greedo
</div>

Stílusattribútum programozása

HTML elem style tulajdonságának olvasása/írása

CSS stílustulajdonság style objektum tulajdonsága
left left
background-color backgroundColor
border-bottom-width borderBottomWidth
border-top-left-radius borderTopLeftRadius

Stílusattribútum programozása

<div style="position: absolute" id="movingElement"></div>
<script>
  document.querySelector("#movingElement").style.top  = "25px";
  document.querySelector("#movingElement").style.left = "42px";
</script>

Objektum stílus

  • elem.style: CSSStyleDeclaration objektum
  • Az összes stílustulajdonságot tartalmazza
  • Tetszőleges tulajdonság beállítható (írás)
  • Lekérdezhető stílustulajdonságok (olvasás):
    • a style attribútumon keresztül voltak megadva;
    • JavaScriptből határoztuk meg az értéküket.

Példa

<style>
.box {
  position: absolute;
  width: 100px; height: 100px;
}
</style>
<div class="box" style="left: 20px"></div>
const box = document.querySelector("div");
box.style.top = "30px";

box.style.top;       // "30px"  <-- JS
box.style.left;      // "20px"  <-- style attribute
box.style.width;     // ""
box.style.position;  // ""

Számított stílus

  • getComputedStyle(elem)
  • A böngésző által nyilvántartott stílustulajdonságok
  • A rövidítések (pl. border, background, stb.) nem érhető el, csak az elemi tulajdonságok.

Példa

<style>
.box {
  position: absolute;
  width: 100px; height: 100px;
}
</style>
<div class="box" style="left: 20px"></div>
const box = document.querySelector("div");
box.top = "30px";

const computedStyle = window.getComputedStyle(box);
computedStyle.top       // "30px"
computedStyle.left      // "20px"
computedStyle.width     // "100px"
computedStyle.position  // "absolute"

Stílusosztály programozása

classList tulajdonság

  • add(className)
  • remove(className)
  • toggle(className)
  • contains(className)

Stílusosztály programozása

add, remove, toggle, contains

<div class="red green blue">
const div = document.querySelector('div');
div.classList.remove("green");
div.classList.add("pink");

// váltogatás
div.classList.toggle("pink");

// feltételes megjelenítés
div.classList.toggle("pink", i < 10);

// van-e adott stílusosztály
div.classList.contains("red");  // true

// több hozzáadása egyszerre
div.classList.add("orange", "yellow");

Eseménykezelés

Interaktív programok

Fogalmak

  • Interaktív programok
  • Felhasználói tevékenység
  • Esemény
  • Eseménykezelő függvények
  • ESEMÉNYVEZÉRELT PROGRAMOZÁS

Eseménykezelő függvények regisztrálása

// Egyszerűbb esetekben
const button = document.querySelector("button");

function handleButtonClick() {
  // mi történjen kattintáskor
}

button.addEventListener("click", handleButtonClick);

Események

  • click: egérkattintás
  • mousemove: egérmozgatás
  • mousedown: egér gombjának lenyomása
  • mouseup: egér gombjának felengedése
  • input: input mező értékének megváltozása
  • keydown: billentyűzet gombjának lenyomása
  • keyup: billentyűzet gombjának felengedése
  • keypress: billentyűzet gombjának megnyomása
  • submit: űrlap elküldése
  • scroll: görgetés az oldalon

Események referenciája

Eseménykezelők mint mini programok

function handleEvent() {
  // Read
  // Process
  // Write
}

Eseménykezelő példa

<form>
  Name: <input type="text" id="name"> <br>
  <input type="button" value="Say hello!" id="hello">
  <br>
  <span id="output"></span>
</form>
function greet(name) {
  return `Hello ${name}!`;
}

const input = document.querySelector('#name');
const output = document.querySelector('#output');
const hello = document.querySelector('#hello');

function handleHelloClick() {
  const name = input.value;
  const greeting = greet(name);
  output.innerHTML = greeting;
}

hello.addEventListener('click', handleHelloClick);

Eseménykezelő függvények regisztrálása

// Egy elem egy eseményéhez több eseménykezelő függvény
button.addEventListener("click", handleButtonClick1);
button.addEventListener("click", handleButtonClick2);

// Több eseményhez ugyanaz az eseménykezelő függvény
button1.addEventListener("click", handleButtonClick);
button2.addEventListener("click", handleButtonClick);

Eseménykezelő hozzárendelése több elemhez

Mi van akkor ha ugyanazt az eseménykezelőt szeretnék sok elemhez hozzárendelni?

Példa

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16

Megoldási ötletek

  1. Eseménykezelő hozzárendelése minden szükséges elemhez
  2. Esemény kezelése magasabb szinten

Eseménykezelő hozzárendelése minden szükséges elemhez

  1. Az összes elem kiválasztása
  2. Eseménykezelő hozzárendelése mindegyikhez
function handleCellClick() { /* ... */ }

const cells = document.querySelectorAll("table td");
for (let cell of cells) {
  cell.addEventListener("click", handleCellClick);
}

Probléma: Mi a helyzet, ha új elemek jönnek létre?

Eseménykezelő kezelése magasabb szinten

  1. Az eseménykezelő hozzárendelése szülő elemhez
  2. Az esemény kezelése a megfelelő szinten

Események buborékolása és delegálása

  • Eseménykezelő függvény: a függvény, ami az esemény bekövetkezésekor lefut
  • Eseményobjektum: az esemény részleteit leíró JavaScript objektum (event)

Események buborékolása és delegálása

  • Buborékolás: az esemény a forrásobjektumtól kezdve sorban mindegyik szülőjén is bekövetkezik
  • Forrásobjektum: az eseményt kiváltó objektum (event.target)
  • Kezelőobjektum: az az objektum, amelyhez az eseménykezelő hozzá van rendelve (this)
  • Lehetséges magasabb szinten kezelni az eseményt, mint ahol bekövetkezik
forrás → szülő → szülő → ... → body → html → document → window

Események buborékolása és delegálása

  • Delegálás: az eseményt magasabb szinten kezeljük, de egy alacsonyabb szintű objektummal dolgozunk
  • Delegált objektum: az az objektum, amellyel az eseménykezelőben dolgozni szeretnénk
  • Buborékolás megakadályozása (a további szülők nem kapják meg az eseményt): e.stopPropagation()
forrás → szülő → szülő → ... → body → html → document → window

Eseménykezelő kezelése magasabb szinten

const table = document.querySelector("table");

function handleCellClick(event) {
  // Run only if the current target is a `td`
  if (!✒>event.target<✒.matches("td"));
  /* ... */
}

table.addEventListener("click", handleTableClick);

Események delegálása

  • Hatékony programozási minta
    (egy elem - egy eseménykezelő)
  • Sok elemnél / valamilyen típusú elemre általánosan
  • Dinamikusan beszúrt elemeknél
  • Viselkedés hozzárendelése elemekhez deklaratívan

Összefoglalás

  • Elemek létrehozása
    • HTML kód generálása
    • Elemek beszúrása programozottan
  • Stílusattribútumok programozása
    • elem.style
    • getComputedStyle
    • classList
  • Eseménykezelés
    • elem.addEventListener(type, handler)
    • Eseményobjektum
    • Buborékolás, delegálás