Bubble.js O soluție 1.6K la o problemă obișnuită

Una dintre cele mai frecvente sarcini în dezvoltarea web este managementul evenimentului. Codul nostru JavaScript ascultă de obicei evenimentele expediate de elementele DOM. 

Acesta este modul în care obținem informațiile de la utilizator: adică el, clicuri, tipuri, interacționează cu pagina noastră și trebuie să știm când se întâmplă acest lucru. Adăugarea ascultătorilor evenimentului pare trivial, dar ar putea fi un proces dificil.

În acest articol, vom vedea o problemă reală a cazului și soluția 1.6K.

Problema

Un prieten de-al meu lucrează ca dezvoltator junior. Ca atare, el nu are o mulțime de experiență cu JavaScript de vanilie; totuși, el a trebuit să înceapă să utilizeze cadre precum AngularJS și Ember fără a avea o înțelegere fundamentală a relației DOM-la-JavaScript. În timpul său ca dezvoltator de juniori, a fost însărcinat cu un mic proiect: site-uri de campanii cu o singură pagină, cu aproape nici un JavaScript implicat. Se confruntă cu o problemă mică, dar foarte interesantă, care în cele din urmă mă face să scriu Bubble.js.

Imaginați-vă că avem un pop-up. Un stil frumos

element:

...

Iată codul pe care îl folosim pentru a afișa un mesaj:

var popup = document.querySelector (". popup"); var showMessage = funcție (msg) popup.style.display = 'bloc'; popup.innerHTML = msg;  ... showMessage ("Încărcare, vă rugăm să așteptați.");

Avem o altă funcție hideMessage care schimba afişa proprietate la nici unul și ascunde popup-ul. Abordarea poate funcționa în cel mai generic caz, dar are încă unele probleme. 

De exemplu, să spunem că trebuie să implementăm o logică suplimentară dacă problemele apar una câte una. Să spunem că trebuie să adăugăm două butoane la conținutul pop-up-ului - da și Nu.

var content = 'Sigur?
„; conținut + = 'Da'; conținut + = 'Nu'; showMessage (conținut);

Deci, cum vom ști că utilizatorul face clic pe ele? Trebuie să adăugăm ascultători de evenimente la fiecare dintre legături. 

De exemplu:

var addListeners = funcția (daCB, noCB) popup.querySelector ('. popup - yes'). addEventListener ('click', yesCB); popup.querySelector (". popup - no"). addEventListener ("clic", nu);  showMessage (conținut); addListeners (functie () console.log ('Da butonul Da clicked');, function () console.log ('Nu apasat butonul'););

Codul de mai sus funcționează în timpul primei runde. Dacă avem nevoie de un buton nou sau chiar mai rău, dacă avem nevoie de un alt tip de buton? Asta este, dacă am continua să folosim  dar cu nume de clasă diferite? Nu putem folosi la fel addListeners și este enervant să creați o nouă metodă pentru fiecare variantă de popup.

Iată unde problemele devin vizibile:

  • Trebuie să adăugăm ascultătorii din nou și din nou. De fapt, trebuie să facem acest lucru de fiecare dată când HTML în pop-up
    s-a schimbat.
  • Am putea atașa ascultătorii evenimentului doar dacă conținutul pop-up-ului este actualizat. Numai după showMessage de asteptare. Trebuie să ne gândim tot timpul și să sincronizăm cele două procese.
  • Codul care adaugă ascultătorilor are o dependență dificilă - Pop-up variabil. Trebuie să-i sunăm querySelector în loc de document.querySelector. În caz contrar, este posibil să selectăm un element greșit.
  • Odată ce schimbăm logica în mesaj, trebuie să schimbăm selectorii și, probabil, addEventListener apeluri. Nu este uscat deloc.

Trebuie să existe o modalitate mai bună de a face acest lucru.

Da, există o abordare mai bună. Și nu, soluția nu este să folosiți un cadru.

Înainte de a dezvălui răspunsul, hai să vorbim puțin despre evenimentele din arborele DOM.

Înțelegerea manipulării evenimentelor

Evenimentele reprezintă o parte esențială a dezvoltării web. Ele adaugă interactivitatea aplicațiilor noastre și acționează ca o punte între logica de afaceri și utilizatorul. Fiecare element DOM poate expedia evenimente. Tot ce trebuie să faceți este să vă abonați la aceste evenimente și să procesați obiectul Eveniment primite.

Există un termen propagarea evenimentului care stă în spatele ei bâzâitul evenimentului și eveniment de captare ambele fiind două moduri de manipulare a evenimentelor în DOM. Să folosim următorul marcaj și să vedem diferența dintre ele.

faceți clic pe mine

Vom atașa clic manipulatoare de evenimente pentru ambele elemente. Cu toate acestea, pentru că sunt împletite unul în celălalt, ambii vor primi clic eveniment.

document.querySelector ('.wrapper') addEventListener ('click', funcția (e) console.log ('. wrapper clicked');); document.querySelector ('a') addEventListener ('click', functie (e) console.log ('a clicked'););

După ce apăsăm pe link, vom vedea următoarea ieșire în consola:

un clic

Deci, într-adevăr, ambele elemente primesc clic eveniment. Mai întâi, legătura și apoi

. Acesta este efectul bubbling. De la cel mai profund element posibil la părinții săi. Există o modalitate de a opri blocajele. Fiecare handler primește un obiect de eveniment care are stopPropagation metodă:

document.querySelector ('a') addEventListener ('click', functie (e) e.stopPropagation (); console.log ('a clicked'););

Prin utilizarea stopPropagation , indicăm faptul că evenimentul nu trebuie trimis părinților.

Uneori este posibil să fie necesar să inversăm ordinea și să avem evenimentul prins de elementul exterior. Pentru a realiza acest lucru, trebuie să folosim un al treilea parametru în addEventListener. Dacă trecem Adevărat ca o valoare pe care o vom face ecaptarea aerului. De exemplu:

document.querySelector ('.wrapper') addEventListener ('click', functie (e) console.log ('. wrapper clicked'); true; document.querySelector ('a') addEventListener ('click', functie (e) console.log ('a clicked'); true;

Acesta este modul în care browserul nostru procesează evenimentele atunci când interacționăm cu pagina.

Soluția

Bine, deci de ce am petrecut o secțiune a articolului vorbind despre bubble și captură Am menționat-le pentru că bubble-ul este răspunsul problemelor noastre cu pop-ul. Ar trebui să setăm ascultătorii evenimentului nu la legături ci la

direct.

var content = 'Sigur?
„; conținut + = 'Da'; conținut + = 'Nu'; var addListeners = funcția () popup.addEventListener ('click', funcția (e) var link = e.target;); showMessage (conținut); addListeners ();

Urmând această abordare, eliminăm problemele enumerate la început.

  • Există un singur ascultător de evenimente și îl adăugăm o singură dată. Indiferent de ceea ce punem în fereastra pop-up, capturarea evenimentelor se va întâmpla în părintele lor.
  • Nu suntem obligați să adăugăm conținut suplimentar. Cu alte cuvinte, nu ne pasă când showMessage se numește. Atâta timp cât Pop-up variabilă este în viață vom prinde evenimentele.
  • Pentru că sunăm addListeners o dată, folosim Pop-up variabilă o dată. Nu trebuie să o păstrăm sau să o trecem printre metode.
  • Codul nostru a devenit flexibil deoarece am optat pentru că nu ne pasă de codul HTML promovat showMessage. Avem acces la ancora clicked în asta e.target indică elementul presat.

Codul de mai sus este mai bun decât cel cu care am început. Cu toate acestea, tot nu funcționează în același mod. Așa cum am spus, e.target arată la clic etichetă. Deci, vom folosi acest lucru pentru a distinge da și Nu butoane.

var addListeners = funcția (callbacks) popup.addEventListener ('click', funcția (e) var link = e.target; var buttonType = link.getAttribute (' Tipul butonului] (e););  ... (*) () () () () () () ;

Am atras valoarea clasă atribuiți și utilizați-l ca o cheie. Diferitele clase indică apeluri diferite.

Cu toate acestea, nu este o idee bună să utilizați clasă atribut. Este rezervată aplicării stilurilor vizuale elementului, iar valoarea lui se poate schimba în orice moment. Ca dezvoltatori JavaScript, ar trebui să folosim date atribute.

var content = 'Sigur?
„; conținut + = 'Da'; conținut + = 'Nu';

Codul nostru devine și mai bun. Putem elimina cotații folosite în addListeners funcţie:

addListeners (yes: function () console.log ('Da');, no: function () console.log ('Nu');

Rezultatul putea fi văzut în acest JSBin.

Bubble.js

Am aplicat soluția de mai sus în mai multe proiecte, așa că a fost logic să-i împachetezi o bibliotecă. Se numește Bubble.js și este disponibil în GitHub. Acesta este fișierul 1.6K care face exact ceea ce am făcut mai sus.

Să transformăm exemplul pop-up de folosit Bubble.js. Primul lucru pe care trebuie să îl schimbăm este marcajul utilizat:

var content = 'Sigur?
„; conținut + = 'Da'; conținut + = 'Nu';

In loc de date de acțiune ar trebui să folosim date-bubble-acțiune.

Odată ce includem bubble.min.js în pagina noastră, avem un global balon funcția disponibilă. Acceptă un selector de elemente DOM și returnează API-ul bibliotecii. pe metoda este cea care adaugă ascultătorilor:

balon ('.upup') .on ('da', functie () console.log ('Da');)) .on (' );

Există, de asemenea, o sintaxă alternativă:

balon ('.popup') la yes: function () console.log ('Yes');, no: function () console.log ('No');

În mod implicit, Bubble.js ascultă clic evenimente, dar există o opțiune de a schimba acest lucru. Să adăugăm un câmp de intrare și îl ascultăm keyup eveniment:

Managerul JavaScript încă primește obiectul Eveniment. Deci, în acest caz, suntem capabili să afișăm textul câmpului:

(... input: function (e) console.log ('Noua valoare:' + e.target.value););

Uneori nu trebuie să prindem decât unul, dar multe evenimente expediate de același element. date-bubble-acțiune acceptă mai multe valori separate prin virgulă:

Găsiți varianta finală într-un JSBin aici.

fallbacks

Soluția oferită în acest articol se bazează complet pe bâzâitul evenimentului. In unele cazuri e.target nu poate indica elementul de care avem nevoie. 

De exemplu:

Vă rog, alege pe mine!

Dacă plasăm mouse-ul peste "alege" și face un clic, elementul care expedia evenimentul nu este eticheta, dar deschidere element.

rezumat

Desigur, comunicarea cu DOM este o parte esențială a dezvoltării aplicațiilor noastre, însă este o practică obișnuită să folosim cadre doar pentru a ocoli această comunicare. 

Nu ne place să adăugăm ascultători din nou și din nou. Nu ne place să debugăm bug-uri ciudate de dublu eveniment. Adevărul este că, dacă știm cum funcționează browserul, putem elimina aceste probleme.

Bubble.js este doar un rezultat al citirii cateva ore si o codare de o ora - este solutia noastra de 1.6K la una dintre cele mai frecvente probleme.