Heim >Web-Frontend >js-Tutorial >Detaillierte Erläuterung der Verwendung des Diff-Algorithmus (mit Code)

Detaillierte Erläuterung der Verwendung des Diff-Algorithmus (mit Code)

php中世界最好的语言
php中世界最好的语言Original
2018-05-08 09:20:001952Durchsuche

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)
       )
      )
     )
    }
  • Dadurch wird bestätigt, ob die beiden Knoten einen weiteren Vergleichswert haben, andernfalls werden sie direkt ersetzt
  • 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;
    }
  • Einfügen Um den Prozess zu vereinfachen, müssen Sie den Typ des Knotens bestimmen und

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
  1. Statischer Knotenvergleichsschlüssel, danach wird kein erneutes Rendern durchgeführt, kopieren Sie direkt die KomponenteInstanz (sobald der Befehl hier wirksam wird)

  2. Wenn vnode ein Textknoten oder ein

    Kommentarknoten
  3. ist, aber wenn vnode.text != oldVnode.text ist, müssen Sie nur den Textinhalt von vnode.elm
  4. Vergleich der untergeordneten Knoten
  5. Wenn nur oldVnode untergeordnete Knoten hat, dann löschen Sie diese Knoten
  6. Wenn nur vnode hat untergeordnete Knoten. Wenn oldVnode ein Textknoten ist, legen Sie den Text von vnode.elm auf eine leere
  7. Zeichenfolge
 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, &#39;&#39;)
    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, &#39;&#39;)
   }
  } 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--

  1. oldStart === newEnd, oldStart is am Ende der Warteschlange eingefügt oldStart++ newEnd--

  2. oldEnd === newStart, oldEnd wird am Anfang der Warteschlange oldEnd-- newStart++

    <🎜 eingefügt >
  3. Dies ist die einfache Möglichkeit, alle verbleibenden Situationen zu bewältigen. Nach der Verarbeitung gibt es newStart++
  • 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中文网其它相关文章!

推荐阅读:

pushState与replaceState使用步骤详解

CSS3二级导航菜单制作步骤详解

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!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn