Sunteți pe pagina 1din 23

Programarea interfețelor grafice

 Curs 5

Programarea prelucrărilor complexe


Evenimente Aplicație

Evenimente
Exploatarea datelor din șirul de obiecte clasa8B se poate realiza în multe moduri. În exemplul scris, rularea codului JavaScris era automată, la
încărcarea în browser a paginii scrise.
Uneori însă, acest comportament al browser-ului nu este adecvat deoarece dorim ca executarea unor funcții JavaScript să fie determinată de acțiuni
asupra unor elemente din interfața grafică a aplicației sau ca urmare a trecerii unui interval de timp.
În informatică funcțiile care sunt lansate astfel (oarecum "automat"), poartă numele de funcții de tip callback.
Funcțiile de tip callback existente în secvențele de cod JavaScript scrise până acum au fost declanșate ca urmare a generării de către browser a unui
eveniment. De fiecare dată evenimentul declanșator al funcției a fost un "clic", funcția fiind asociată evenimentului folosind următoarea construcție
sintactică (Cursul 1):

document.querySelector("#calcul").onclick = calculTabla;

A fost menționată de asemenea sintaxa alternativă:

document.querySelector("#calcul").addEventListener("click", calculTabla);
Datorită modului de apelare, funcția calculTabla este o funcție de tip callback.
Majoritatea funcțiilor de tip callback care vor fi scrise vor fi de altfel asociate evenimentelor de tip "clic".

Explicații suplimentare: Limbajul JavaScript este soluția pentru impunerea modului în care aplicația web va reacționa la acțiunile operatorului.
Acțiunile acestuia asupra unor elemente HTML declanșează evenimente care apoi pot fi tratate de funcții din cadrul aplicației web. Evenimentele
tratate mai frecvent sunt:

 clic - menționat deja, declanșat când este selectat cu mausul un element HTML;
 mouseover - declanșat când cursorul mausului este plasat peste un element HTML;
 mouseout - declanșat când cursorul mausului părăsește dreptunghiul de încadrare al unui element HTML;
 change – declanșat când se modifică starea sau conținutul unui element destinat interacțiunii cu operatorul (un <input> de
tip text, checkbox, select, etc);
 submit – declanșat când operatorul selectează un buton de tip submit al unui formular.

Valoarea primită de o funcție de tip callback apelată pentru tratare a unui eveniment este un obiect JavaScript de tip event. Din multitudinea de
proprietăți pe care le are un obiect de tip event, cea mai utilizată este target. Această proprietate permite identificarea elementului HTML care a
declanșat un anumit eveniment. Acest lucru este important în cazul în care aceeași funcție de tip callback trebuie declanșată de elemente HTML
diferite.
Exemplu:

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1">

<link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet'>


<title>Evenimente</title>

<style>

body { padding: 30px; font-family: Roboto, sans-serif; }

h2 {margin: 20px; }

.drept { width: 100px; height: 50px; padding: 10px; margin: 20px; background-color: blue; color: white; display: inline-
block; }

</style>

</head>

<body>

<h2>Demo evenimente</h2>

<div class="umbra drept" id="elclic">Aștept clic.</div>

<div class="umbra drept">Blocul 2.</div>

<div class="umbra drept">Blocul 3.</div>

<button id="calcul" class="umbra">Calculează!</button>

<script>

"use strict";
const efectClic = evn => {

const bloc = evn.target;

bloc.innerHTML = "L-am primit!";

bloc.style.color = "blue";

bloc.style.backgroundColor = "yellow";

};

document.querySelector("#elclic").addEventListener("click", efectClic);

const cuUmbrire = (eveniment) => {

const bloc = eveniment.target; // elementul pe care este cursorul

bloc.style.boxShadow = "0 10px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.29)";

const faraUmbrire = (eveniment) => {

const bloc = eveniment.target; // elementul pe care este cursorul


bloc.style.boxShadow = ''; // Anulez efectul de umbrire

const elemUmbrite = [... document.querySelectorAll(".umbra")]; // Selectare multipla.

const umbrire = (item) => {

item.addEventListener("mouseover", cuUmbrire);

item.addEventListener("mouseout", faraUmbrire);

};

elemUmbrite.map(umbrire);

</script>

</body>

</html>
Analiza exemplului:
Codul HTML începe prin declararea unui titlu (<h2>) după care sunt inserate trei elemente <div> (trei dreptunghiuri) și un <button>.
Elementelor cărora dorim să le impunem un efect de umbrire (la suprapunerea cursorului mouse-ului, eng. mouseover) li s-a atașat aceeași clasă CSS
(clasa umbra).
Pentru a atașa fiecăruia dintre elementele având clasa umbra perechea de funcții de tratare cuUmbrire respectiv faraUmbrire declanșate de
evenimentele mouseover respectiv mouseout, s-a creat șirul de obiecte JavaScript elemUmbrite (un array) scriind:

const elemUmbrite = [... document.querySelectorAll(".umbra")];


Apoi folosind funcția map(), fiecărui element din șirul creat i s-au atașat funcții de tratare a evenimentelor mouseover și mouseout. Pentru mai multă
claritate, funcția necesară în map() a fost definită separat.

const umbrire = (item) => {

item.addEventListener("mouseover", cuUmbrire);

item.addEventListener("mouseout", faraUmbrire);

};

elemUmbrite.map(umbrire);

Observații:

 Funcțiile de tip callback pot fi scrise și fără parametru. Scrise astfel, ele nu vor primi acel obiect de tip event menționat. Acest mod de scriere
este folosit dacă în funcție nu sunt necesare valori a căror accesare necesită cunoașterea obiectului de tip event. În exemplele care vor urma vor
fi atât funcții simple, care nu utilizează obiectul de tip event, cât și funcții mai "tehnice", care au nevoie de informațiile conținute în obiectul de
tip event generat automat când se crează evenimentul, ca în exemplul anterior.
 Funcția querySelectorAll() din exemplul precedent se folosește pentru a selecta mai multe elemente care îndeplinesc o condiție. Pentru a o
putea utiliza, clasa CSS umbra a fost adăugată tuturor elementelor HTML care urmau să constituie un șirul de elemente. Clasa umbra nu are o
descriere, rolul ei este doar cel menționat: să permită crearea unui șir de valori folosind querySelectorAll(). Elementelor din șirul de obiecte
astfel creat li s-a putut apoi impune un comportament comun definit de funcțiile cuUmbrire() și faraUmbrire().
 Funcțiile querySelector() și querySelectorAll() sunt înrudite. Prima va fi folosită pentru selectarea unui element HTML care are definit un
atribut id. Sintaxa utilizată este următoarea:

const obiectSelectat = querySelector("#valoareID");

A doua funcție, querySelectorAll() va fi folosită pentru crearea șirurilor de elemente HTML care urmează să sufere aceeași tratare. Pentru selectarea
acestora, tuturor elementelor care trebuie selectate li se va adăuga aceeași clasă CSS. Sintaxa utilizată va fi următoarea:
const sirObiecte = [ ...querySelectorAll(.numeClasa)];

 Funcțiile querySelector() și querySelectorAll() sunt mai recent intrate în limbajul JavaScript. În exemplele din Internet care prezintă secvențe de
cod în care este necesară selectarea unuia sau sau mai multor elemente HTML, sunt folosite frecvent funcțiile
echivalente getElementById() respectiv getElementByClassName(). Explicații suplimentare privind selectarea elementelor HTML în vederea
modificării lor folosind JavaScript pot fi citite aici

TOP

Aplicație
În continuare vor fi realizate mai multe prelucrări folosind datele din șirul de obiecte JavaScript clasa8B.
Pentru declanșarea diverselor afișări, aplicației i s-a adăugat o bară de navigare laterală, ca în imagine:
Rezolvarea se bazează pe această soluție. De altfel la această adresă pot fi găsite multe soluții punctuale pentru probleme specifice paginilor web.
Codul fișierului index.html, în prima variantă, este următorul:

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1">

<link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet'>

<link href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css' rel='stylesheet'>

<title>Clasa a 8-a B</title>

<link rel="stylesheet" href="stiluri.css">

</head>

<body>

<nav>
<div id="elevi" class="meniu"><i class="fa fa-genderless" aria-hidden="true"></i> Elevii clasei</div>

<div id="baieti" class="meniu"><i class="fa fa-mars" aria-hidden="true"></i> Elevii clasei (băieți)</div>

<div id="fete" class="meniu"><i class="fa fa-venus" aria-hidden="true"></i> Elevii clasei (fete)</div>

<div id="note" class="meniu"><i class="fa fa-graduation-cap" aria-hidden="true"></i> Notele la o materie</div>

<div id="tnote" class="meniu"><i class="fa fa-graduation-cap" aria-hidden="true"></i> Notele la toate materiile</div>

<div id="absente" class="meniu"><i class="fa fa-minus-square-o" aria-hidden="true"></i> Absențe</div>

<div id="contact" class="meniu"><i class="fa fa-envelope-o" aria-hidden="true"></i> Contact</div>

</nav>

<main>

<h2 id="titlu">Clasa a 8-a B, Școala Generală Măgura</h2>

<div id="continut" class="centrat">

<img src="img1.jpg" alt="" />

</div>

</main>

<script src="caietDirig.js"></script>
<script>

const el = document.querySelector("#continut");

el.classList.add("centrat");

</script>

</body>

</html>

Fișierul stiluri.css poate fi accesat aici.
În fișierul index.html, în <body> există două elemente de tip bloc, un <h2>, destinat afișării unui titlu, și un <div> pentru conținutul dorit. Ambele
elemente au atribute id deoarece vor fi modificate dinamic, folosind secvențe de cod JavaScript.
În momentul încărcării, aplicațiile web expun ecranul principal. În cazul aplicației destinată afișării unor date despre elevii unei clase, ecranul principal
conține un titlu (Clasa a 8-a B, Școala Generală Măgura, afișat de elementul <h2>) și o imagine (img1.png, conținută în elementul <div
id="continut">).

Aplicațiile web constau de regulă dintr-un singur fișier, index.html. Conținutul afișat de aplicație depinde de starea acesteia. Aplicația începută expune
în stânga ecranului un meniu vertical iar selectarea uneia dintre opțiunile afișate (Elevii clasei, Elevii clasei (băieți), Elevii clasei (fete), Notele la o
materie, Absențe și Contact) va determina afișarea pe ecranul principal a informațiilor cerute.
Observație: În index.html este evidențiată o secvență de cod JavaScript care adaugă elementului <div id="continut"> clasa CSS "centrat". Această
clasă este definită în fișierul stiluri.css.

const el = document.querySelector("#continut");

el.classList.add("centrat");
În alte stări ale aplicației, în care conținutul afișat nu trebuie centrat, clasa centrat va trebui suprimată. Aceasta se realizează folosind funcția remove():

const el = document.querySelector("#continut");

el.classList.remove("centrat");

Afișarea elevilor clasei


În cursul trecut s-a realizat o primă afișare a elevilor clasei folosind funcțiile map() și reduce().
În cazul aplicației curente, afișarea elevilor va trebui să fie comandată de selectarea cu mausul a elementului <div id="elevi" class="meniu"><i
class="fa fa-genderless" aria-hidden="true"></i> Elevii clasei </div> .

Pentru a trata evenimentul "clic" declanșat de selectarea elementului menționat, elementul <script> a fost completat astfel:

<script>

// Cod necesar afisarii ecranului principal

const el = document.querySelector("#continut");

el.classList.add("centrat");

const afiElevi = () => { // Afisez elevii clasei

// Modific titlul
document.querySelector("#titlu").innerHTML = "Elevii clasei a 8-a B";

// Sterg clasa "centrat" pentru blocul "continut"

const el = document.getElementById("continut");

el.classList.remove("centrat");

const elevi = clasa8B

.map(item => { return `${item.nume.toUpperCase()} ${item.prenume}` })

.reduce((html, item) => { return html + `<li>${item}</li>` }, "<ol>") + "</ol>";

document.querySelector("#continut").innerHTML = elevi;

};

document.querySelector("#elevi").onclick = afiElevi;

</script>

Spre deosebire de versiunea din cursul precedent, codul care realizează afișarea elevilor a fost inclus într-o funcție JavaScript (funcția de
tip callback afiElevi()). Declanșarea automată a executării acesteia, ca urmare a selectării elementului corespunzător din meniul aplicației, este
determinată de linia:
document.querySelector("#elevi").onclick = afiElevi;

Afișarea băieților din clasă


Afișarea băieților din clasă presupune realizarea unei filtrări a obiectelor, respectiv reținerea doar a celor care au proprietatea gen: "M".
Scriptului JavaScript scris deja i se va adăuga următoarea secvență de cod:

const afiBaieti = () => { // Afisez baietii

document.querySelector("#titlu").innerHTML = "Elevii clasei (baieti)";

// Sterg clasa "centrat" pentru blocul "continut"

const el = document.getElementById("continut");

el.classList.remove("centrat");

const baieti = item => {

if (item.gen === "M") {

return true;

return false;
}

const elevi = clasa8B

.filter(baieti)

.map(item => { return `${item.nume.toUpperCase()} ${item.prenume}` })

.reduce((html, item) => { return html + `<li>${item}</li>` }, "<ol>") + "</ol>";

document.querySelector("#continut").innerHTML = elevi;

};

document.querySelector("#baieti").onclick = afiBaieti;

Pentru o scriere mai compactă a șirului de funcții utilizat pentru producerea conținutului blocului <div id="continut">, funcția necesară la apelarea
funcției filter() (denumită baieti()) a fost scrisă separat. Ea returnează valoarea logică true dacă obiectul pentru care a fost apelată are
proprietatea gen: "M" și false în caz contrar.
Ce se mai poate remarca este faptul că funcția baieti() este conținută în funcția de tip callback afiBaieti().
Rezultat:
Afișarea fetelor din clasă
Pentru afișarea fetelor din clasă, singura modificare necesară codului precedent (care afișează băieții) este funcția apelată de filter():

const afiFete = () => { // Afisez fetele

document.querySelector("#titlu").innerHTML = "Elevii clasei (fete)";

// Sterg clasa "centrat" pentru blocul "continut"


const el = document.getElementById("continut");

el.classList.remove("centrat");

const fete = item => {

if (item.gen === "F") {

return true;

return false;

const elevi = clasa8B

.filter(fete)

.map(item => { return `${item.nume.toUpperCase()} ${item.prenume}` })

.reduce((html, item) => { return html + `<li>${item}</li>` }, "<ol>") + "</ol>";

document.querySelector("#continut").innerHTML = elevi;
};

document.querySelector("#fete").onclick = afiFete;

Rezultat:

Afișarea absențelor elevilor


Pentru a afișa numărul de absențe ale fiecărui elev se poate folosi proprietatea .length, care permite preluarea numărului de elemente dintr-un șir.
const afiAbsente = () => { // Afisez absentele elevilor

document.querySelector("#titlu").innerHTML = "Numărul de absente";

// Sterg clasa "centrat" pentru blocul "continut"

const el = document.getElementById("continut");

el.classList.remove("centrat");

const absElev = item => {

return `${item.nume.toUpperCase()} ${item.prenume}: ${item.absente.length}`;

};

// Construiesc lista

const nrAbsente = clasa8B

.map(absElev)

.reduce((html, item) => { return html + `<li>${item}</li>` }, "<ol>") + "</ol>";


document.querySelector("#continut").innerHTML = nrAbsente;

};

document.querySelector("#absente").onclick = afiAbsente;

Pentru o scriere mai compactă a șirului de funcții utilizat pentru producerea conținutului blocului <div id="continut">, funcția necesară la apelarea
funcției map() (denumită absElev()) a fost scrisă separat.
Rezultat:
TOP

S-ar putea să vă placă și