ÜberblickMan kann sagen, dass der Diff-Algorithmus ein Kerninhalt von Vue ist. Ich habe Vue vorher nur für einige Entwicklungsarbeiten verwendet und wusste nicht viel über den spezifischen Kerninhalt. Vor kurzem habe ich zufällig einige Inhalte in diesem Bereich gelesen. Lassen Sie uns über die Implementierung des Diff-Algorithmus von Vue2.0 sprechen. Insbesondere werden wir ihn anhand mehrerer implementierter Funktionen analysieren. Virtueller DomVirtueller DOM extrahiert die Daten des realen DOM und simuliert die Baumstruktur in Form von Objekten. Zum Beispiel ist das Folgende unser realer DOM <div> <p>1234</p> <div> <span>1111</span> </div> </div> Der entsprechend dem realen DOM generierte virtuelle DOM sieht wie folgt aus var Vnode = { Tag: 'div', Kinder: [ { Tag: 'p', Text: '1234' }, { Tag: 'div', Kinder:[ { Tag: 'span', Text: '1111' } ] } ] } PrinzipDas Prinzip von Diff besteht darin, dass der aktuelle reale DOM einen virtuellen DOM erzeugt. Wenn sich die Daten eines Knotens im virtuellen DOM ändern, wird ein neuer Vnode erzeugt. Anschließend wird dieser Vnode mit dem alten oldVnode verglichen. Wenn ein Unterschied besteht, wird dieser direkt im realen DOM geändert. ImplementierungsprozessDer Kern des Implementierungsprozesses des Diff-Algorithmus ist Patch. Die Methoden patchVnode, sameVnode und updateChildren verdienen unsere Aufmerksamkeit. Im Folgenden werden sie der Reihe nach erläutert. Patch-MethodeDie Kernlogik von Patch besteht darin, zwei Vnode-Knoten zu vergleichen und dann die Unterschiede in der Ansicht zu aktualisieren. Die Vergleichsmethode ist ein Peer-Vergleich, anstatt jede Ebene zu durchlaufen. Wenn nach dem Vergleich Unterschiede gefunden werden, werden diese Unterschiede in der Ansicht aktualisiert. Das Beispiel für die Vergleichsmethode lautet wie folgt sameVnode-FunktionDie Funktion von sameVnode besteht darin, zu bestimmen, ob zwei Knoten gleich sind. Grundlage für die Bestimmung sind Schlüsselwert, Tag, isCommit, ob der Eingabetyp konsistent ist usw. Diese Methode weist einige Mängel auf. In Situationen, in denen der Schlüsselwert unter v-for einen Index verwendet, kann er auch als wiederverwendbarer Knoten beurteilt werden. Es wird empfohlen, den Index nicht als Schlüsselwert zu verwenden. patchVnode-Funktion// Mehrere Parameter übergeben, oldVnode stellt den alten Knoten dar, vnode stellt den neuen Knoten dar, readOnly stellt dar, ob es sich um eine schreibgeschützte Knotenfunktion handelt patchVnode ( alterVnode, vKnoten, eingefügteVnodeQueue, BesitzerArray, Index, Nur entfernen ) { if (oldVnode === vnode) { //Wenn der alte Knoten und der neue Knoten konsistent sind, ist kein Vergleich erforderlich, return return } wenn (isDef(vnode.elm) und isDef(ownerArray)) { // wiederverwendeten vnode klonen vnode = BesitzerArray[Index] = Klon-VNode(vnode) } const elm = vnode.elm = alterVnode.elm wenn (istTrue(oldVnode.isAsyncPlaceholder)) { wenn (isDef(vnode.asyncFactory.gelöst)) { hydratisieren(alterVnode.elm, vnode, eingefügteVnodeQueue) } anders { vnode.isAsyncPlaceholder = true } zurückkehren } //Elemente des statischen Baums wiederverwenden //Das machen wir nur, wenn der Vnode geklont ist. //Wenn der neue Knoten nicht geklont ist, bedeutet das, dass die Rendering-Funktion geklont wurde. //Zurückgesetzt über Hot-Reload-API, und wir müssen ein richtiges erneutes Rendering durchführen. wenn (isTrue(vnode.isStatic) && isTrue(alterVnode.isStatic) && vnode.key === alterVnode.key && (istWahr(vnode.isCloned) || istWahr(vnode.isOnce)) ) { vnode.componentInstance = alteVnode.componentInstance zurückkehren } lass mich const data = vnode.data wenn (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) { i(alterV-Knoten, V-Knoten) } const oldCh = oldVnode.children const ch = vnode.children wenn (isDef(data) und isPatchable(vnode)) { für (i = 0; i < cbs.update.length; ++i) cbs.update[i](alterVnode, vnode) wenn (isDef(i = data.hook) und isDef(i = i.update)) i(alterVnode, vnode) } wenn (isUndef(vnode.text)) { wenn (isDef(alterCh) und isDef(ch)) { wenn (alterKanal !== ch) updateChildren(elm, alterKanal, ch, eingefügteVnodeQueue, nurentfernen) } sonst wenn (isDef(ch)) { wenn (Prozess.Umgebung.NODE_ENV !== 'Produktion') { checkDuplicateKeys(ch) } wenn (isDef(alterVnode.text)) nodeOps.setTextContent(elm, '') addVnodes(elm, null, ch, 0, ch.length - 1, eingefügteVnodeQueue) } sonst wenn (isDef(oldCh)) { removeVnodes(alterKanal, 0, alterKanal.Länge - 1) } sonst wenn (isDef(alterVnode.text)) { nodeOps.setTextContent(ulme, '') } } sonst wenn (alterVnode.text !== vnode.text) { nodeOps.setTextContent(elm, vnode.text) } wenn (isDef(Daten)) { wenn (isDef(i = data.hook) und isDef(i = i.postpatch)) i(alterVnode, vnode) } } Die spezifische Implementierungslogik ist:
updateChildren-FunktionupdateChildren ist, wie der Name schon sagt, eine Methode zum Aktualisieren von untergeordneten Knoten. Aus der obigen patchVnode-Methode können wir ersehen, dass diese Methode ausgeführt wird, wenn sowohl der neue als auch der alte Knoten untergeordnete Knoten haben. Werfen wir einen Blick auf die Implementierungslogik. Es gibt auch einige Beispieldiagramme, die Ihnen vielleicht schon einmal ähnlich erschienen sind. Werfen wir zunächst einen Blick auf den Code. Funktion updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) { let oldStartIdx = 0 let newStartIdx = 0 let oldEndIdx = alteCh.Länge - 1 let oldStartVnode = oldCh[0] let oldEndVnode = oldCh[oldEndIdx] let newEndIdx = newCh.length - 1 lass newStartVnode = newCh[0] let newEndVnode = newCh[newEndIdx] let oldKeyToIdx, idxInOld, vnodeToMove, refElm // removeOnly ist ein spezielles Flag, das nur von <transition-group> verwendet wird // um sicherzustellen, dass entfernte Elemente an den richtigen relativen Positionen bleiben // während des Verlassens von Übergängen const canMove = !removeOnly wenn (Prozess.Umgebung.NODE_ENV !== 'Produktion') { checkDuplicateKeys(neuerSchlüssel) } während (alteStartIdx <= alteEndIdx && neueStartIdx <= neueEndIdx) { wenn (isUndef(alterStartVnode)) { oldStartVnode = oldCh[++oldStartIdx] // Vnode wurde nach links verschoben } sonst wenn (isUndef(oldEndVnode)) { oldEndVnode = alterCh[--oldEndIdx] } sonst wenn (gleicherVnode(alterStartVnode, neuerStartVnode)) { patchVnode(alterStartVnode, neuerStartVnode, eingefügteVnodeQueue, neuerCh, neueStartIdx) alterStartVnode = alterCh[++alteStartIdx] neuerStartVnode = neuerCh[++neueStartIdx] } sonst wenn (gleicherVnode(alterVnodeEndknoten, neuerVnodeEndknoten)) { patchVnode(alterEndVnode, neuerEndVnode, eingefügteVnodeQueue, neuerCh, neueEndIdx) oldEndVnode = alterCh[--oldEndIdx] neuerEndVnode = neuerCh[--newEndIdx] } sonst wenn (sameVnode(oldStartVnode, newEndVnode)) { // Vnode nach rechts verschoben patchVnode(alterStartVnode, neuerEndVnode, eingefügteVnodeQueue, neuerCh, neueEndIdx) kann verschieben && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm)) alterStartVnode = alterCh[++alteStartIdx] neuerEndVnode = neuerCh[--newEndIdx] } sonst wenn (sameVnode(oldEndVnode, newStartVnode)) { // Vnode nach links verschoben patchVnode(alterEnd-Vnode, neuerStart-Vnode, eingefügteVnodeQueue, neuerCh, neueStartIdx) kann verschieben und nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm) oldEndVnode = alterCh[--oldEndIdx] neuerStartVnode = neuerCh[++neueStartIdx] } anders { wenn (isUndef(alterKeyToIdx)) alterKeyToIdx = createKeyToOldIdx(alterCh, alteStartIdx, alteEndIdx) idxInOld = isDef(neuerStartVnode.key) ? oldKeyToIdx[neuerStartVnode.key] : findIdxInOld(neuerStartVnode, alterCh, alteStartIdx, alteEndIdx) if (isUndef(idxInOld)) { // Neues Element createElm(neuerStartVnode, eingefügteVnodeQueue, übergeordneteElm, alterStartVnode.elm, false, neuerCh, neueStartIdx) } anders { vnodeToMove = alterCh[idxInOld] wenn (sameVnode(vnodeToMove, newStartVnode)) { patchVnode(ZuVerschiebender vnode, neuerStartVnode, eingefügteVnodeQueue, neuerCh, neueStartIdx) oldCh[idxInOld] = undefiniert kann verschieben und nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm) } anders { // gleicher Schlüssel, aber anderes Element. Als neues Element behandeln createElm(neuerStartVnode, eingefügteVnodeQueue, übergeordneteElm, alterStartVnode.elm, false, neuerCh, neueStartIdx) } } neuerStartVnode = neuerCh[++neueStartIdx] } } wenn (alteStartIdx > alteEndIdx) { refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, eingefügteVnodeQueue) } sonst wenn (neueStartIdx > neueEndIdx) { removeVnodes(alterCh, alteStartIdx, alteEndIdx) } } Hier definieren wir zunächst mehrere Parameter: oldStartIdx (erster Index des alten Knotens), oldEndIdx (letzter Index des alten Knotens), oldStartVnode (erstes Element des alten Knotens), oldEndVnode (letztes Element des alten Knotens); analog dazu sind newStartIdx und die anderen vier Elemente der erste Index des neuen Knotens usw. Schauen Sie sich die Operationen in der while-Schleife an, die auch den Kerninhalt darstellen Nachdem festgestellt wurde, dass es sich um denselben Knoten handelt, muss der Knoten auch mit der Methode patchVnode fortfahren
Wenn ein Vnode mit demselben Schlüssel wie newStartVnode gefunden wird, wird er vnodeToMove genannt und dann wird vnodeToMove mit newStartVnode verglichen. Wenn sie gleich sind, werden beide erneut gepatcht. Wenn removeOnly falsch ist, wird der Vnode mit demselben Schlüssel wie newStartVnode, genannt vnodeToMove.elm, vor oldStartVnode.elm verschoben. Wenn der Schlüsselwert gleich ist, die Knoten jedoch unterschiedlich sind, wird ein neuer Knoten erstellt. Wenn nach der While-Schleife noch Knoten im neuen oder alten Knoten-Array vorhanden sind, löschen oder fügen Sie diese je nach spezifischer Situation hinzu. Wenn oldStartIdx > oldEndIdx ist, bedeutet dies, dass oldCh zuerst durchlaufen wird, was bedeutet, dass es neue Knoten gibt, die redundant sind. Neue Knoten hinzufügen Wenn newStartIdx > newEndIdx, bedeutet dies, dass der neue Knoten zuerst durchlaufen wird und noch alte Knoten übrig sind. Löschen Sie daher die verbleibenden Knoten. Schauen wir uns das Beispielbild unten an Ursprünglicher Knoten (oldVnode ist der alte Knoten, Vnode ist der neue Knoten und diff ist das nach dem Diff-Algorithmus generierte Knotenarray) Beim ersten Durchlaufen stellen wir fest, dass das alte Endelement mit dem neuen ersten Element identisch ist. Daher wird das alte Endelement D vor den alten ersten Index verschoben, also vor A. Gleichzeitig wird der alte Endindex nach links und der neue erste Index nach rechts verschoben. Beim zweiten Durchlauf der Schleife ist das neue erste Element dasselbe wie das alte erste Element. Zu diesem Zeitpunkt ändern sich die Positionen der beiden Elemente nicht, und die neuen und alten ersten Indizes verschieben sich gleichzeitig nach rechts. Die dritte Schleife stellt fest, dass es im alten Element keinen Knoten gibt, der mit dem aktuellen Element identisch ist. Daher wird ein neuer hinzugefügt und F wird vor das alte erste Element gesetzt. In ähnlicher Weise verhält es sich mit der vierten Schleife. Nach zwei Schleifen wird ein neues Beispieldiagramm generiert. Der fünfte Zyklus ist derselbe wie der zweite Zyklus. In der sechsten Schleife bewegt sich newStartIdx wieder nach rechts 7. Nach dem letzten Zug ist newStartIdx > newEndIdx und die while-Schleife wurde verlassen, was beweist, dass newCh zuerst durchlaufen wird und oldCh noch zusätzliche Knoten hat, die direkt gelöscht werden, sodass der letzte Knoten Oben sind mehrere Funktionen im Zusammenhang mit dem Diff-Algorithmus und dem Implementierungsprozess des Diff-Algorithmus aufgeführt. AbschlussDer Diff-Algorithmus ist ein zentraler Bestandteil des virtuellen DOM. Er vergleicht dieselbe Ebene und aktualisiert die geänderten Teile mit dem realen DOM, indem er die neuen und alten Knoten vergleicht. Die spezifischen Implementierungsmethoden sind patch, patchVnode und updateChildren Der Kern des Patches besteht darin, dass, wenn der neue Knoten existiert, der alte Knoten jedoch nicht, dieser hinzugefügt wird; wenn der alte Knoten existiert, der neue jedoch nicht, dieser gelöscht wird; wenn beide existieren, festgestellt wird, ob sie identisch sind; wenn sie identisch sind, patchVnode für den nächsten Vergleichsschritt aufgerufen wird. Der Kern von patchVnode lautet: Wenn die neuen und alten Knoten keine Kommentare oder Textknoten sind und der neue Knoten untergeordnete Knoten hat, der alte jedoch nicht, fügen Sie einen untergeordneten Knoten hinzu. Wenn der neue Knoten keine untergeordneten Knoten hat, der alte Knoten jedoch untergeordnete Knoten hat, löschen Sie die untergeordneten Knoten unter dem alten Knoten. Wenn beide untergeordnete Knoten haben, rufen Sie die Methode updateChildren auf. Dies ist nur eine vorläufige Erklärung des Diff-Algorithmus von Vue2.0. Die tieferen Prinzipien und ob es Änderungen im Diff-Algorithmus von Vue3.0 gibt, müssen noch herausgefunden werden. Dies ist das Ende dieses Artikels über den Diff-Algorithmus in Vue. Weitere Informationen zum Diff-Algorithmus von Vue finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen! Das könnte Sie auch interessieren:
|
<<: Grafisches Tutorial zur Installation und Konfiguration von MySQL 8.0.20
>>: Installations- und Konfigurationstutorial von MongoDB unter Linux
Durch die Verwendung der virtuellen Domänennamenk...
Detailliertes Beispiel zum Entfernen doppelter Da...
In vielen Projekten ist es notwendig, die Funktio...
Funktionen zu Null in MySql IFNULL ISNULL NULLIF ...
Vorwort Ich habe einige Beispiele mit Vue3 geschr...
Inhaltsverzeichnis Vorwort Einführung in QueryCac...
<br />Informationsduplikation, Informationsü...
Hinweis 1: Der gesamte Hintergrund im obigen Bild...
Vorwort Js ist heutzutage die am häufigsten verwe...
Datenbanksicherung #Grammatik: # mysqldump -h ser...
Inhaltsverzeichnis 01 sql_slave_skip_counter-Para...
Einführung in Struktur und Leistung HTML-Struktur...
Umsetzungsideen Erstellen Sie zunächst einen über...
Problem <br />Bei responsivem Layout sollte...
Die Hauptunterschiede sind folgende: 1. MySQL ver...