Heim >Web-Frontend >js-Tutorial >Detaillierte Erläuterung der Verwendung des Diff-Algorithmus (mit Code)
Dieses Mal werde ich Ihnen die Verwendung des Diff-Algorithmus (mit Code) ausführlich erklären. Was sind die Vorsichtsmaßnahmen bei der Verwendung des Diff-Algorithmus? .
Virtueller Dom
Der Diff-Algorithmus muss zunächst das Konzept klären, dass das Objekt von Diff der virtuelle Dom ist und die Aktualisierung des realen Doms das Ergebnis des Diff-Algorithmus ist
Vnode-Basisklasse
constructor ( 。。。 ) { this.tag = tag this.data = data this.children = children this.text = text this.elm = elm this.ns = undefined this.context = context this.fnContext = undefined this.fnOptions = undefined this.fnScopeId = undefined this.key = data && data.key this.componentOptions = componentOptions this.componentInstance = undefined this.parent = undefined this.raw = false this.isStatic = false this.isRootInsert = true this.isComment = false this.isCloned = false this.isOnce = false this.asyncFactory = asyncFactory this.asyncMeta = undefined this.isAsyncPlaceholder = false }
Dieser Teil des Codes dient hauptsächlich dazu, die Bedeutung des Attributs des spezifischen Diff im Diff besser zu verstehen Algorithmus. Natürlich kann es auch besser sein, die Vnode-Instanz zu verstehen
Der Gesamtprozess
Die Kernfunktion ist die Patch-Funktion
isUndef-Urteil (ob es undefiniert oder null ist)
// leerer Mount (wahrscheinlich als Komponente), neues Root-Element erstellencreateElm(vnode, insertedVnodeQueue) Hier finden Sie das Das Erstellen von Knoten wird nicht einzeln eingefügt, sondern in eine Warteschlange für die einheitliche Stapelverarbeitung gestellt Vergleichsfunktion, die den Schlüssel und das Tag zweier Knoten direkt vergleicht, Daten vergleicht (beachten Sie, dass sich Daten hier auf VNodeData beziehen) und Typen für die Eingabe direkt vergleicht.
function sameVnode (a, b) { return ( a.key === b.key && ( ( a.tag === b.tag && a.isComment === b.isComment && isDef(a.data) === isDef(b.data) && sameInputType(a, b) ) || ( isTrue(a.isAsyncPlaceholder) && a.asyncFactory === b.asyncFactory && isUndef(b.asyncFactory.error) ) ) ) }
Der Ersetzungsprozess ist hauptsächlich eine createElm-Funktion und die andere besteht darin, den oldVNode zu zerstören
export interface VNodeData { key?: string | number; slot?: string; scopedSlots?: { [key: string]: ScopedSlot }; ref?: string; tag?: string; staticClass?: string; class?: any; staticStyle?: { [key: string]: any }; style?: object[] | object; props?: { [key: string]: any }; attrs?: { [key: string]: any }; domProps?: { [key: string]: any }; hook?: { [key: string]: Function }; on?: { [key: string]: Function | Function[] }; nativeOn?: { [key: string]: Function | Function[] }; transition?: object; show?: boolean; inlineTemplate?: { render: Function; staticRenderFns: Function[]; }; directives?: VNodeDirective[]; keepAlive?: boolean; }
createComponent aufrufen (es ermittelt, ob Kinder vorhanden sind, und ruft es dann rekursiv auf)
createComment
createTextNode
nach der Erstellung Nachdem Sie die Einfügefunktion
verwendet haben, müssen Sie die Hydrate-Funktion verwenden, um den virtuellen Dom und den realen Dom abzubilden
// destroy old node if (isDef(parentElm)) { removeVnodes(parentElm, [oldVnode], 0, 0) } else if (isDef(oldVnode.tag)) { invokeDestroyHook(oldVnode) }
Kernfunktion
function insert (parent, elm, ref) { if (isDef(parent)) { if (isDef(ref)) { if (ref.parentNode === parent) { nodeOps.insertBefore(parent, elm, ref) } } else { nodeOps.appendChild(parent, elm) } } }const el = vnode.el = oldVnode.el Dies ist ein sehr wichtiger Schritt, wenn el auf den aktuellen realen Dom verweist , vnode.el wird sich synchron ändern.
Vergleichen Sie, ob die beiden Referenzen konsistent sind
Ich weiß nicht, was asyncFactory danach macht, also kann ich es nicht Verstehen Sie diesen Vergleich
Statischer Knotenvergleichsschlüssel, danach wird kein erneutes Rendern durchgeführt, kopieren Sie direkt die KomponenteInstanz (sobald der Befehl hier wirksam wird)
Wenn vnode ein Textknoten oder ein
KommentarknotenupdateChildren
function patchVnode (oldVnode, vnode, insertedVnodeQueue, removeOnly) { if (oldVnode === vnode) { return } const elm = vnode.elm = oldVnode.elm if (isTrue(oldVnode.isAsyncPlaceholder)) { if (isDef(vnode.asyncFactory.resolved)) { hydrate(oldVnode.elm, vnode, insertedVnodeQueue) } else { vnode.isAsyncPlaceholder = true } return } if (isTrue(vnode.isStatic) && isTrue(oldVnode.isStatic) && vnode.key === oldVnode.key && (isTrue(vnode.isCloned) || isTrue(vnode.isOnce)) ) { vnode.componentInstance = oldVnode.componentInstance return } let i const data = vnode.data if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) { i(oldVnode, vnode) } const oldCh = oldVnode.children const ch = vnode.children if (isDef(data) && isPatchable(vnode)) { for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode) if (isDef(i = data.hook) && isDef(i = i.update)) i(oldVnode, vnode) } if (isUndef(vnode.text)) { if (isDef(oldCh) && isDef(ch)) { if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly) } else if (isDef(ch)) { if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, '') addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue) } else if (isDef(oldCh)) { removeVnodes(elm, oldCh, 0, oldCh.length - 1) } else if (isDef(oldVnode.text)) { nodeOps.setTextContent(elm, '') } } else if (oldVnode.text !== vnode.text) { nodeOps.setTextContent(elm, vnode.text) } if (isDef(data)) { if (isDef(i = data.hook) && isDef(i = i.postpatch)) i(oldVnode, vnode) } }Mehrere Situationen und Verarbeitung eines Schleifenvergleichs (das folgende ++ -- bezieht sich alle auf das ++ des Index --) Der Vergleich ist der zu vergleichende Knotenknoten und der Vergleich verwendet die sameVnode-Funktion. Es ist nicht wirklich kongruent.
Die Bedingung dafür, dass die gesamte Schleife nicht endet oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx
oldStart = == newStart, oldStart++ newStart++oldEnd === newEnd, oldEnd-- newEnd--newStart在old中发现一样的那么将这个移动到oldStart前
没有发现一样的那么创建一个放到oldStart之前
循环结束后并没有完成
还有一段判断才算完
if (oldStartIdx > oldEndIdx) { refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue) } else if (newStartIdx > newEndIdx) { removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx) }
简单的说就是循环结束后,看四个指针中间的内容,old数组中和new数组中,多退少补而已
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der Verwendung des Diff-Algorithmus (mit Code). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!