Kliensoldali webprogramozás

A tárgy ismertetése. Ismétlés. Progresszív fejlesztés.

Horváth Győző
Egyetemi docens
1117 Budapest, Pázmány Péter sétány 1/c., 4.725-as szoba
horvath.gyozo@inf.elte.hu

Kontextus

Előzmények

  • Webprogramozás tárgy
  • Statikus vs dinamikus
  • Kliens és szerver
  • Alap szintű, natív
  • Függvénykönyvtárak nélkül
  • Keretrendszerek nélkül

Szerver evolúció

  • Statikus weboldalak
  • 1995-2000
    • dinamikus weboldalak
    • JS (!), PHP, Perl
  • 2000-
    • hatalmas fejlődés, vállalati rendszerek
    • tervezési minták
    • Java, ASP.NET
    • webszolgáltatások
  • 2000: REST
  • 2001: Drupal, Wordpress

Szerver evolúció

  • 2005: Microszervíz architektúrák
  • 2008: Node.js
  • 2011: WebSocket
  • 2015
    • HTTP/2
    • GraphQL

Kliens evolúció

  • Statikus weboldalak
  • 1995-2000
    • dinamikus weboldalak
    • JS, Java, Flash
    • 1. böngészőháború
  • 2000-2006
    • Sötét középkor
    • 2. böngészőháború

Kliens evolúció

  • 2006-2010
    • AJAX
    • JS nyelv újrafelfedezése
    • programozási minták
    • Cross-browser
    • Progresszív fejlesztés (unobtrusive JS)
    • 3. böngészőháború
    • Képessé tétel alkalmazások futtatására
  • 2010-2014
    • tervezési minták
    • MV*
  • 2014-
    • Komponensalapú fejlesztés

Érdekességek

A tárgy ismertetése

A tárgyról

https://canvas.elte.hu/

  • Kliensoldali webprogramozás
  • Architektúra
  • Tervezési minták
  • Technológia
  • Eszközök
  • Fogalmak
  • Nyelvfüggetlen/implementáció

Ismétlés

Web

  • HTTP
  • URL
  • HTML

→ Böngésző API

JavaScript

C++, dinamikus, OOP, funkcionális

class Library {
  books = [
    {title: 'A case for Christ', author: 'Lee Strobel'},
    // ...
  ]
  booksByAuthor(author) {
    return this.books.filter(book => book.author === author)
  }
}

const lib = new Library()
const strobels = lib.booksByAuthor('Lee Strobel')
for (const b of strobels) {
  console.log(b.title);
}

DOM

  • HTML elemek belső ábrázolása
  • programozási interfész (API)
  • bemeneti-kimeneti interfész

  • Elemek kiválasztása
    • document.querySelector('css selector')
    • document.querySelectorAll('css selector')
  • Elem (JavaScript objektum) tulajdonságai
    • Webfejlesztés → Webprogramozás
    • tulajdonságok, írás/olvasás
    • stílusok
    • faműveletek

Eseménykezelés

  • elem.addEventListener(típus, fgv)
  • Interakció eszköze
  • mini-programok
  • Eseményobjektum
  • Alapértelmezett műveletek megakadályozása
  • Buborékolás
  • Delegálás

További ismeretek

  • Űrlap, táblázat, képek
  • Nyelvi elemek
  • HTML5 API-k
    • tárolás
    • Canvas
    • Window API
  • Kódszervezési elvek
    • adat-nézet szétválasztása
    • imperatív-deklaratív UI kezelés
    • függvények, osztályok, modulok használata

Weboldalak progresszív fejlesztése

Progressive enhancement

Történeti pozíció

2006-2010

  • erős szerveroldali környezet
  • JS életre kelése
  • cross-browser problémák
  • felhasználóbarátság-igény

Relevancia és hatáskör

  • Hatáskör
    • Tartalomközpontú oldalak
    • CMS rendszerek oldalai
    • Landing page-ek
  • Relevancia
    • Sokféle eszköz
    • Filozófia

Weboldal vs webalkalmazás

Weboldal Webalkalmazás
Tartalom Funkció
Működik JS nélkül JS kell hozzá
Fogyasztás Létrehozás
Egyszerű Komplex
Szerveroldali Kliensoldali

Probléma

  • Mi történik, ha olyan funkciót használunk, amely nem mindenhol érhető el?
  • Például
    • Eredetileg: nincs JavaScript
    • vállalati beállítások
    • idősebb eszközök
    • limitált erőforrású eszközök (pl. hűtő)
  • Két irány
    • könnyed lefokozás
    • progresszív fejlesztés

Könnyed lefokozás

  • Graceful degradation (GD)
  • Célja: felhasználó funkcionálisan használhassa a felületet
  • Megközelítés: hiba tolerálása
  • Ha egy komplex rendszer egy vagy több komponensébe hiba csúszik, akkor egy alternatív útvonalon biztosítja a működést
  • Ld. noscript tag, alt attribútum, táblázat mint layout, canvas fallback content

Progresszív fejlesztés

  • Progressive enhancement (PE)
  • Cél ugyanaz, de a megközelítés más
  • Különböző felhasználók és eszközök támogatása
  • Egy közös alap (HTML) létrehozása a cél, amit minden eszköz megért, erre jön rá a CSS és a JavaScript
  • Az alapelv: tartalom, stílus és viselkedés szétválasztása

GD vs PE

Könnyed lefokozás Progresszív fejlesztés
Kiindulás: teljes funkcionalitású verzió Kiindulás: alap funkció
Ha valami nem elérhető, akkor azt kihagyva érhető el a funkció Ha valami elérhető, akkor azt elérhetővé teszi
Fentről lefele építkezik Lentről felfele építkezik

Progresszív fejlesztés

  • Lépések
    1. szerkezet (szemantikus HTML)
    2. megjelenés, stílus (CSS)
    3. viselkedés (JavaScript)

PE előnyei

  • JavaScript nélkül működik
  • Sokféle eszközön fut
  • Akadálymentesség jobb biztosítása
  • lentről felfelé építkezik → tisztább, modulárisabb kód
  • jövőben is kompatibilis marad az oldal

Progresszív fejlesztés példák

Forrás: Todd Parker, Scott Jehl, Maggie Costello Wachs, Patty Toland: Designing with Progressive Enhancement: Building the Web that Works for Everyone, 1st Edition

Nyomtatás

Nagyon régi kód :)

<p id="printthis">
  <a href="javascript:window.print()">Print this page</a>
</p>

Forrás

Könnyed lefokozás

  • Mi az a JavaScript?
  • Hogyan kell bekapcsolni?
  • Van jogom bekapcsolni?
<p id="printthis">
  <a href="javascript:window.print()">Print this page</a>
</p>
<noscript>
  <p class="scriptwarning">
    Printing the page requires JavaScript to be enabled. 
    Please turn it on in your browser.
  </p>
</noscript>

Progresszív fejlesztés

Kell egyáltalán nyomtatás funkció?

<p id="printthis">Thank you for your order. Please print this page for your records.</p>
const pt = document.getElementById('printthis');
if(pt && typeof window.print === 'function'){
  const but = document.createElement('input');
  but.setAttribute('type','button');
  but.setAttribute('value','Print this now');
  but.onclick = function(){
    window.print();
  };
  pt.appendChild(but);
}

Címlap

Analizálás

Menü

Kiemelt cikkek

Szűrt cikkek

Űrlap

Fejlesztett változat

Űrlap

Alap változat

Tooltip

Fejlesztett változat

Tooltip

Alap változat

Modális dialógusablak

Progresszív fejlesztés eszközei

Külső függvénykönyvtárak

  • Rengeteg kész függvénykönyvtár van
  • Nem kell mindent nekünk megírni
  • JS-nek van a legnagyobb repoja (Module counts)

CDN

Content Delivery Network

CDN

  • Statikus assetek gyors kiszolgálása
    • Függvénykönyvtárak
    • Stílusok, fontok
  • Világon elszórt szerverek – közeli kiszolgálás
  • Cache policy-k
  • Példák

CDN

<!-- index.html -->
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>
<script src="index.js"></script>
// index.js
_.countBy([6.1, 4.2, 6.3], Math.floor);
// => { '4': 1, '6': 2 }

Gyakori események

  • scroll, resize események nagyon gyakran hívódhatnak meg
  • nem szabad erőforrásigényes logikát írni bennük
  • csökkenteni kell az eseménykezelések számát → throttling

Throttling

// custom throttle
let waiting = false
window.addEventListener('scroll', function (e) {
    if (!waiting) {
        doSomething()
        window.requestAnimationFrame(function () {
            waiting = false
        });
        waiting = true
    }
});
// lodash throttle metódus
window.addEventListener('scroll', _.throttle(doSomething, 100))

Méretek

  • window
    • scrollY (pageYOffset)
    • innerHeight
    • outerHeight

Méretek

Element.clientHeight: mekkora a megjelenített tartalom

Méretek

Element.offsetHeight: mekkora helyet foglal

Méretek

  • rect = Element.getBoundingClientRect()
    • mekkora helyet foglal, transzformációkkal együtt
    • pozíciója a viewporthoz képest
  • Pozíció a dokumentumhoz képest
    • rect.top + window.scrollY

Méretek

Element.scrollHeight: az elem tartalmának magassága (a nem láthatóakkal együtt)

Méretek

  • Element.scrollTop
    • mennyit gördült az elem
    • <html> elemnél = window.scrollY
  • Teljes gördítés ellenőrzése
    • element.scrollHeight - element.scrollTop === element.clientHeight
  • Element.clientTop: felső keret vastagsága
  • Element.offsetTop: az elemnek az offsetParent-től való távolsága

Méretek

Forrás

Méretek

Forrás

Méretek

Forrás

Intersection observer

  • Mikor jelenik meg egy elem a másik gördítése során?
  • 1. megoldás: requestAnimationFrame()
  • 2. megoldás: IntersectionObserver
const observer = new IntersectionObserver(onObserve, {
  threshold: 0.0,
})
function onObserve(entries) {
  entries.forEach(entry => console.log(entry))
}
observer.observe(target)

Mutation observer

  • Változások figyelése
const mutationObserver = new MutationObserver(onMutate)
function onMutate(records) {
  records.forEach(record => console.log(record));
}
mutationObserver.observe(document.body, {
  subtree: true,
  childList: true,
  attributes: true
})

Végszó

  • Progresszív fejlesztés
  • Függvénykönyvtárak alkalmazása
  • Hasznos böngésző API-k