Cum să vă scrieți propriul domiciliu virtual - devschacht - mediu

Traducerea articolului "deathmood": Cum să-ți scrieți propriul DOM virtual

Există două lucruri pe care trebuie să le cunoașteți pentru a vă scrie propriul DOM virtual. Nu trebuie nici măcar să vă aruncați în codul sursă React sau codul sursă al oricărei alte implementări a DOM-ului virtual. Ele sunt atât de mari și complexe, dar în realitate, cea mai mare parte a DOM-ului virtual poate fi scrisă în mai puțin de 50 de linii de cod. 50. Linii. Cod.

Există două concepte aici:

  • Virtual DOM - orice reprezentare a actualului DOM
  • Când schimbăm ceva în arborele nostru virtual virtual, vom crea un nou copac virtual. Algoritmul compară cei doi arbori (vechi și noi), găsește diferența și face doar modificările minime necesare la actualul DOM, astfel încât să se potrivească cu cel virtual.

Asta e tot! Să intrăm în fiecare dintre aceste concepte.

Vederea arborelui nostru DOM

Mai întâi trebuie să stocăm cumva arborele DOM în memorie. Și putem face acest lucru cu simple obiecte JS. Să presupunem că avem acest copac:

Arată simplu, nu-i așa? Cum ne putem imagina folosind obiecte simple JS:

Aici puteți observa două lucruri:

  • Noi reprezentăm elementele DOM în vizualizarea obiectului
  • Descriim noduri de text cu șiruri JS simple

Dar este destul de dificil să scrieți copaci mari în acest fel. Deci, să scriem o funcție auxiliară, astfel încât să devină mai ușor pentru noi să înțelegem structura:

Acum putem descrie arborele nostru DOM în această formă:

Arată mult mai curat, nu-i așa? Dar putem merge mai departe. Ai auzit de JSX, nu-i așa? Da, aș dori să-i aplic ideile aici. Deci, cum funcționează?

Dacă citiți documentația oficială a lui Babel către JSX aici. știi că Babel va traduce acest cod:

în ceva de genul:

De fapt, ea îi spune lui Babel: "Hei, compilați acest jsx, dar în loc de React.createElement. înlocuiți h. " Aici puteți înlocui orice pentru h. Și va fi compilat.

Deci, vom scrie DOM astfel:

Și va fi compilat de Babel în următorul cod:

Executarea funcției h va returna un simplu obiect JS - reprezentarea noastră a DOM-ului virtual.

Încercați-vă singur pe JSFiddle (nu uitați să specificați Babel ca limbă).

Aplicând vizualizarea DOM

Ei bine, acum avem o vedere a arborelui nostru DOM în obiectul JS, cu structura proprie. Este minunat, dar trebuie să creăm într-un fel un DOM real. Desigur, nu putem doar să aplicăm punctul nostru de vedere DOM.

Mai întâi de toate, să stabilim câteva ipoteze și să definim terminologia:

  • Voi scrie toate variabilele care stochează nodurile DOM actuale (elemente, noduri de text), începând cu $. astfel încât $ parent este un element DOM adevărat
  • O reprezentare DOM virtual va fi stocată într-o variabilă numită nod
  • Ca și în React, puteți avea doar un singur nod rădăcină, toate celelalte noduri vor fi în interior

Acum, după ce l-am sortat, să scriem funcția createElement (...), care va lua un nod DOM virtual și va returna nodul DOM real. Uită de recuzită și de copii. ne vom ocupa mai tarziu de ei:

Astfel, putem trece atât noduri virtuale de text, cât și noduri de elemente virtuale, iar acest lucru va funcționa.

Acum să ne gândim la copii: fiecare dintre ele este și un nod sau element de text. Prin urmare, ele pot fi create folosind funcția createElement (...). Simți că? Miroase de recursion :)) Deci, putem apela createElement (...) pentru fiecare element de copil, apoi appendChild () în elementul nostru după cum urmează:

Wow, arată grozav. Să lăsăm acum deoparte nodurile de recuzită. Vom vorbi mai târziu despre ele. Nu avem nevoie de ele pentru o înțelegere de bază a conceptelor DOM virtuale și vor adăuga doar complexitatea.

Să mergem mai departe și să încercăm acest lucru în JSFiddle.

Modificări de procesare

Acum, putem transforma DOM-ul nostru virtual într-un DOM real, este timpul să ne gândim la compararea copacilor virtuali. Trebuie să scriem un algoritm care să compare doi arbori virtuali - vechi și noi - și să facă doar modificările necesare în actualul DOM.

Cum comparați copacii? Trebuie să rezolvăm următoarele situații:

  • Dacă nu există nici un nod vechi într-un anumit loc: nodul a fost adăugat și trebuie să folosim appendChild (...)
  • Nu există un nod nou într-un anumit loc: acest nod a fost eliminat și trebuie să folosim removeChild (...)
  • Un alt nod în acest loc: nodul sa schimbat și trebuie să folosim replaceChild (...)
  • Nodurile sunt aceleași: trebuie să mergem mai adânc și să comparăm nodurile copilului

Să scriem funcția updateElement (...), care are trei parametri: $ parent, newNode și oldNode. $ parent este părintele DOM real al nodului nostru virtual. Acum vedem cum să rezolvăm toate situațiile descrise mai sus.

Dacă nu există nici un nod vechi

Dacă nu există nod nou

Aici avem o problemă: dacă nu există niciun nod într-un anumit loc în noul copac virtual, trebuie să îl eliminăm din DOM real. Dar cum se poate face acest lucru? Știm elementul părinte (este trecut la funcție) și, prin urmare, trebuie să sunăm $ parent.removeChild (...) și să trimitem referința la elementul DOM real. Dar nu avem. Dacă știm poziția nodului nostru în părinte, am putea obține referința lui cu $ parent.childNodes [index], unde indexul este poziția nodului nostru în elementul părinte.

Să presupunem că acest index va fi transmis funcției noastre (și se va întâmpla într-adevăr, după cum veți vedea mai târziu), atunci codul nostru va fi astfel:

Noda sa schimbat

Mai întâi, trebuie să scriem o funcție care compară cele două noduri și ne spune dacă nodul sa schimbat cu adevărat. Trebuie să ținem seama că poate fi fie elemente, fie noduri text:

Și acum, având indicele nodului nod curent, îl putem înlocui ușor cu nodul nou creat:

Compararea elementelor copilului

Nu în ultimul rând, trebuie să trecem prin fiecare element copil în ambele noduri, să le comparăm și să sunăm updateElement (...) pentru fiecare dintre ele. Da, din nou, recurență.

Dar există câteva lucruri care trebuie luate în considerare înainte de a scrie codul:

  • Trebuie să comparăm copiii dacă nodul este un element (nodurile de text nu pot avea copii)
  • Acum trimitem referința la nodul curent ca părinte
  • Ar trebui să comparăm toți copiii unul câte unul, chiar dacă la un moment dat ne-am definit (acest lucru este normal, funcția noastră știe să o facă)
  • În cele din urmă, indexul este doar un indicator pentru un nod copil în matricea copiilor

Punând totul împreună

Da, așa este. Am ajuns acolo. Am pus tot codul în JSFiddle și punerea în aplicare este de fapt 50 LOC, așa cum ți-am promis. Puteți merge și să vă jucați cu el.

Deschideți instrumentele pentru dezvoltatori și vedeți cum apar schimbările la apăsarea butonului Reîncărcare.

concluzie

Felicitări! Am făcut-o. Am scris implementarea DOM-ului virtual. Și funcționează. Sper că după ce ați citit acest articol, înțelegeți conceptele de bază și modul în care trebuie să funcționeze DOM-ul virtual și cum funcționează React sub capotă.

  • Setarea atributelor elementului și compararea și actualizarea acestora
  • Adăugarea de agenți de procesare a evenimentelor pentru elementele noastre
  • Capacitatea DOM-ului nostru virtual de a lucra cu componente precum React
  • Obținerea de linkuri către nodurile DOM reale
  • Folosind un DOM virtual cu biblioteci care mută direct un DOM real: jQuery și plugin-urile acestuia
  • Și mult mai mult ...