Analyse des Implementierungsprinzips von Vue-Anweisungen

Analyse des Implementierungsprinzips von Vue-Anweisungen

1. Grundlegende Verwendung

Offizielle Website Fall:

<div id='App'>
  <Eingabetyp="Text" v-Modell="Eingabewert" v-Fokus>
</div>
<Skript>
  Vue.direktive('Fokus', {
    // Rufe bind() auf, wenn du ein Element zum ersten Mal bindest {
      console.log('binden')
    },
    // Wenn das gebundene Element in das DOM eingefügt wird ...
    eingefügt: Funktion (el) {
      console.log('eingefügt')
      el.fokus()
    },
    // Rufe update() auf, wenn die Komponente VNode aktualisiert ist {
      console.log('aktualisieren')
    },
    // Rufen Sie componentUpdated() auf, nachdem alle VNode und seine untergeordneten VNodes der Komponente, in der sich die Anweisung befindet, aktualisiert wurden {
      console.log('Komponente aktualisiert')
    },
    // Wird nur einmal aufgerufen. unbind() wird aufgerufen, wenn die Anweisung vom Element { gelöst wird.
      console.log('aufheben')
    }
  })
  neuer Vue({
    Daten: {
      Eingabewert: ''
    }
  }).$mount('#app')
</Skript>

2. Funktionsweise der Anweisungen

2.1. Initialisierung

Rufen Sie beim Initialisieren der globalen API unter Plattformen/Web die Funktion createPatchFunction auf, um die Patch-Methode zu generieren, die VNode in das echte DOM konvertiert. Ein wichtiger Schritt bei der Initialisierung ist die Definition der Hook-Methoden, die den DOM-Knoten entsprechen. Während der Erstellung (create), Aktivierung (avtivate), Aktualisierung (update), Entfernung (remove) und Zerstörung (destroy) des DOM werden die entsprechenden Hook-Methoden abgefragt und jeweils aufgerufen. Einige dieser Hooks sind die Eingänge zum Befehlsdeklarationszyklus.

// src/core/vdom/patch.js
const hooks = ['erstellen', 'aktivieren', 'aktualisieren', 'entfernen', 'zerstören']
Exportfunktion createPatchFunction (Backend) {
  sei i, j
  const cbs = {}

  const { module, nodeOps } = backend
  für (i = 0; i < hooks.length; ++i) {
    cbs[Haken[i]] = []
    // Module entsprechen Modulen in Vue, einschließlich Klasse, Stil, DomListener, DomProps, Attrs, Direktive, Ref, Übergang
    für (j = 0; j < Module.Länge; ++j) {
      wenn (isDef(Module[j][Hooks[i]])) {
        // Schließlich Hooks in {hookEvent: [cb1, cb2 ...], ...} von cbs[hooks[i]].push(modules[j][hooks[i]]) umwandeln.
      }
    }
  }
  // ....
  Rückgabefunktionspatch (alterVnode, vnode, hydratisieren, nur entfernen) {
    // ...
  }
}

2.2 Vorlagenkompilierung

Die Vorlagenkompilierung dient zum Parsen der Anweisungsparameter. Das spezifische dekonstruierte ASTElement lautet wie folgt:

{
  Tag: 'Eingabe',
  übergeordnetes Element: ASTElement,
  Anweisungen: [
    {
      arg: null, // Parameterende: 56, // Endzeichenposition der Anweisung isDynamicArg: false, // dynamischer Parameter, v-xxx[dynamicParams]='xxx' Formaufrufmodifikatoren: nicht definiert, // Name des Anweisungsmodifikators: „model“,
      rawName: "v-model", // Befehlsname Start: 36, // Befehlsstartzeichenposition Wert: "inputValue" // Vorlage },
    {
      arg: null,
      Ende: 67,
      isDynamicArg: false,
      Modifikatoren: undefiniert,
      Name: "Fokus",
      Rohname: "v-focus",
      Beginn: 57,
      Wert: ""
    }
  ],
  // ...
}

2.3. Rendering-Methode generieren

Vue empfiehlt die Verwendung von Anweisungen zum Bedienen von DOM. Da benutzerdefinierte Anweisungen DOM oder Attribute ändern können, vermeiden Sie die Auswirkungen von Anweisungen auf die Vorlagenanalyse. Beim Generieren von Rendering-Methoden müssen zuerst Anweisungen wie v-model verarbeitet werden, was im Wesentlichen ein syntaktischer Zucker ist. Beim Spleißen von Rendering-Funktionen werden den Elementen Wertattribute und Eingabeereignisse hinzugefügt (am Beispiel der Eingabe kann dies auch vom Benutzer angepasst werden).

mit (diesem) {
    return _c('div', {
        Attribute: {
            "id": "App"
        }
    }, [_c('Eingabe', {
        Anweisungen: [{
            Name: "Modell",
            rawName: "v-Modell",
            Wert: (Eingabewert),
            Ausdruck: "Eingabewert"
        }, {
            Name: "Fokus",
            Rohname: "v-focus"
        }],
        Attribute: {
            "Typ": "Text"
        },
        domProps: {
            "value": (inputValue) // Attribute, die bei der Verarbeitung von v-model-Anweisungen hinzugefügt werden},
        An: {
            "input": function($event) { // Benutzerdefiniertes Ereignis, das bei der Verarbeitung der V-Model-Direktive hinzugefügt wird, wenn ($event.target.composing)
                    zurückkehren;
                Eingabewert = $event.target.value
            }
        }
    })])
}

2.4. VNode generieren

Das Design der Vue-Anweisungen soll unseren DOM-Betrieb erleichtern. Beim Generieren von VNode führen die Anweisungen keine zusätzlichen Verarbeitungsvorgänge aus.

2.5. Echtes DOM generieren

Während des Vue-Initialisierungsprozesses müssen wir zwei Punkte beachten:

  • Die Initialisierung des Status ist übergeordnet -> untergeordnet, z. B. beforeCreate, created, beforeMount, die Aufrufreihenfolge ist übergeordnet -> untergeordnet
  • Die Montagereihenfolge des echten DOM ist Kind -> Elternteil, z. B. montiert. Dies liegt daran, dass beim Generieren des echten DOM, wenn eine Komponente angetroffen wird, der Komponentenerstellungsprozess befolgt wird. Die Generierung des echten DOM wird Ebene für Ebene vom Kind zum Elternteil gespleißt.

Während des Patch-Prozesses wird jedes Mal, wenn createElm aufgerufen wird, um das echte DOM zu generieren, festgestellt, ob der aktuelle VNode ein Datenattribut hat. Wenn dies der Fall ist, wird invokeCreateHooks aufgerufen, um die am Anfang erstellte Hook-Funktion auszuführen. Der Kerncode lautet wie folgt:

// src/core/vdom/patch.js
Funktion createElm (
    vKnoten,
    eingefügteVnodeQueue,
    übergeordnete Ulme,
    sieheElm,
    verschachtelt,
    BesitzerArray,
    Index
  ) {
    // ...
    // createComponent hat einen Rückgabewert, also die Methode zum Erstellen von Komponenten. Wenn es keinen Rückgabewert gibt, fahren Sie mit der folgenden Methode fort, if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
      zurückkehren
    }

    const data = vnode.data
    // ....
    wenn (isDef(Daten)) {
        // Nachdem der reale Knoten erstellt wurde, aktualisiere die Knotenattribute, einschließlich der Anweisung // Die Anweisung ruft die Bind-Methode zum ersten Mal auf und initialisiert dann die nachfolgende Hook-Methode der Anweisung invokeCreateHooks(vnode, insertedVnodeQueue)
    }
    // Von unten nach oben, einfügen(parentElm, vnode.elm, refElm)
    // ...
  }

Oben sehen Sie den ersten Eintrag der Direktiven-Hook-Methode. Es ist an der Zeit, das Geheimnis von directive.js zu lüften. Der Kerncode lautet wie folgt:

// src/core/vdom/modules/directives.js

// Standardmäßig sind alle ausgelösten Methoden updateDirectives method export default {
  erstellen: updateDirectives,
  aktualisieren: Update-Richtlinien,
  zerstören: Funktion unbindDirectives (vnode: VNodeWithData) {
    // Wenn zerstört, vnode === emptyNode
    Update-Direktiven(vnode, leererKnoten)
  }
}

Funktion updateDirectives (alter Vnode: VNodeWithData, vnode: VNodeWithData) {
  wenn (alteVnode.data.directives || vnode.data.directives) {
    _update(alterVnode, vnode)
  }
}

Funktion _update (alterVnode, vnode) {
  const isCreate = alterVnode === leererNode
  const isDestroy = vnode === leerer Knoten
  const oldDirs = normalizeDirectives(alterVnode.data.directives, alterVnode.context)
  const newDirs = normalizeDirectives(vnode.data.directives, vnode.context)
  // Rückruf nach dem Einfügen const dirsWithInsert = [
  // Rückruf nach Abschluss des Updates const dirsWithPostpatch = []

  let-Schlüssel, oldDir, dir
  für (Schlüssel in newDirs) {
    oldDir = oldDirs[Schlüssel]
    dir = newDirs[Schlüssel]
    // Neuer Elementbefehl, führt die eingefügte Hook-Methode einmal aus, wenn (!oldDir) {
      // neue Direktive, binden
      callHook(dir, 'binden', vnode, alter Vnode)
      if (dir.def && dir.def.inserted) {
        dirsWithInsert.push(dir)
      }
    } anders {
      // bestehende Direktive, Update
      // Wenn das Element bereits existiert, wird die componentUpdated-Hook-Methode dir.oldValue = oldDir.value einmal ausgeführt
      dir.oldArg = altesDir.arg
      callHook(dir, 'update', vnode, alter vnode)
      wenn (dir.def && dir.def.componentUpdated) {
        dirsWithPostpatch.push(dir)
      }
    }
  }

  if (dirsWithInsert.length) {
    // Das echte DOM wird in die Seite eingefügt und diese Callback-Methode wird aufgerufen const callInsert = () => {
      für (lass i = 0; i < dirsWithInsert.length; i++) {
        callHook(dirsWithInsert[i], 'eingefügt', vnode, alterVnode)
      }
    }
    // VNode Merge-Insert-Hooks
    wenn (ist erstellt) {
      mergeVNodeHook(vnode, 'insert', callInsert)
    } anders {
      callInsert()
    }
  }

  if (dirsWithPostpatch.Länge) {
    mergeVNodeHook(vnode, 'postpatch', () => {
      für (lass i = 0; i < dirsWithPostpatch.length; i++) {
        callHook(dirsWithPostpatch[i], 'Komponente aktualisiert', vnode, alter Vnode)
      }
    })
  }

  wenn (!istErstellen) {
    für (Schlüssel in oldDirs) {
      wenn (!newDirs[Schlüssel]) {
        // nicht mehr vorhanden, Bindung aufheben
        callHook(alteDirs[Schlüssel], 'aufheben', alterV-Knoten, alterV-Knoten, isDestroy)
      }
    }
  }
}

Bei der ersten Erstellung läuft die Ausführung folgendermaßen ab:

1.oldVnode === emptyNode, isCreate ist true und alle Bind-Hook-Methoden im aktuellen Element werden aufgerufen.

2. Überprüfen Sie, ob die Anweisung einen eingefügten Hook enthält. Wenn ja, fügen Sie den eingefügten Hook in die Eigenschaft VNode.data.hooks ein.

3. Nachdem die DOM-Montage abgeschlossen ist, wird invokeInsertHook für alle montierten Knoten ausgeführt, wenn in VNode.data.hooks ein Einfüge-Hook vorhanden ist. Es wird aufgerufen und die an die Anweisung gebundene eingefügte Methode wird ausgelöst.

Im Allgemeinen werden für die erste Erstellung nur die Methoden „Bind“ und „Insert“ verwendet, während „Update“ und „ComponentUpdated“ den Methoden „Bind“ und „Insert“ entsprechen. Wenn sich der Abhängigkeitsstatus der Komponente ändert, wird der VNode-Diff-Algorithmus zum Patchen des Knotens verwendet. Der Aufrufvorgang läuft wie folgt ab:

1. Wenn sich die Reaktionsdaten ändern, rufen Sie dep.notify auf, um über Datenaktualisierungen zu benachrichtigen.

2. Rufen Sie patchVNode auf, um differenzielle Aktualisierungen an den neuen und alten VNodes durchzuführen und die aktuellen VNode-Attribute vollständig zu aktualisieren (einschließlich Anweisungen, die in die Methode updateDirectives gelangen).

3. Wenn die Anweisung über eine Update-Hook-Methode verfügt, rufen Sie die Update-Hook-Methode auf, initialisieren Sie den ComponentUpdated-Rückruf und mounten Sie die Postpatch-Hooks in VNode.data.hooks.

4. Nachdem der aktuelle Knoten und seine untergeordneten Knoten aktualisiert wurden, werden die Postpatch-Hooks ausgelöst, dh die componentUpdated-Methode der Anweisung

Der Kerncode lautet wie folgt:

// src/core/vdom/patch.js
Funktion patchVnode (
    alterVnode,
    vKnoten,
    eingefügteVnodeQueue,
    BesitzerArray,
    Index,
    Nur entfernen
  ) {
    // ...
    const oldCh = oldVnode.children
    const ch = vnode.children
    // Knotenattribute vollständig aktualisieren if (isDef(data) && 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 (isDef(Daten)) {
    // Postpatch-Hook aufrufen, wenn (isDef(i = data.hook) und isDef(i = i.postpatch)) i(oldVnode, vnode)
    }
  }

Die Methode „unbind“ ruft „invokeDestroyHook“ auf, wenn der Knoten zerstört wird. Dies wird hier nicht näher beschrieben.

3. Hinweise

Bei der Verwendung benutzerdefinierter Anweisungen weist das V-Modell noch einige Unterschiede zur normalen Datenbindung von Vorlagen auf. Obwohl beispielsweise der von mir übergebene Parameter (v-xxx = 'param') ein Referenztyp ist, kann er bei Datenänderungen weder das Binden noch das Einfügen der Anweisung auslösen. Dies liegt daran, dass im Deklarationszyklus der Anweisung Binden und Einfügen nur einmal bei der Initialisierung aufgerufen werden und danach nur Update und ComponentUpdated verwendet werden.

Die Ausführungsreihenfolge im Deklarationslebenszyklus einer Direktive lautet binden -> eingefügt -> aktualisieren -> componentUpdated. Wenn eine Direktive vom Inhalt einer untergeordneten Komponente abhängen muss, wird empfohlen, die entsprechende Geschäftslogik in componentUpdated zu schreiben.

In Vue werden viele Methoden in einer Schleife aufgerufen, z. B. Hook-Methoden, Event-Callbacks usw. Im Allgemeinen werden die Aufrufe in Try-Catch gekapselt. Dies soll verhindern, dass eine Verarbeitungsmethode einen Fehler meldet und das gesamte Programm zum Absturz bringt. Dies kann als Referenz in unserem Entwicklungsprozess verwendet werden.

IV. Zusammenfassung

Als ich begann, mir den gesamten Vue-Quellcode anzusehen, wusste ich über viele Details und Methoden nicht viel. Indem ich die Implementierung jeder einzelnen Funktion klärte, konnte ich mir allmählich ein Gesamtbild von Vue verschaffen und gleichzeitig einige Fallstricke bei der Entwicklung und Verwendung vermeiden.

Oben finden Sie den detaillierten Inhalt der Analyse des Implementierungsprinzips der Vue-Direktive. Weitere Informationen zum Prinzip der Vue-Direktive finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Erste Schritte mit benutzerdefinierten Anweisungen in Vue 3.0
  • Detaillierte Erläuterung der benutzerdefinierten Vue-Anweisungen und ihrer Verwendung
  • So erstellen Sie ein Drag & Drop-Plugin mit benutzerdefinierten Vue-Direktiven
  • Detaillierte Erläuterung der benutzerdefinierten Anweisungen zur Vue.js-Quellcodeanalyse
  • Benutzerdefinierter Vue-V-HAS-Befehl zum Implementieren der Schaltflächenberechtigungsbeurteilung
  • Vue Grundanleitung Beispiel grafische Erklärung
  • Zusammenfassung der Entwicklung benutzerdefinierter Vue 3-Richtlinien
  • Wissenszusammenfassung zu benutzerdefinierten Anweisungen (Direktiven) für Vue3.0
  • 8 sehr praktische benutzerdefinierte Vue-Anweisungen
  • Detaillierte Erklärung der benutzerdefinierten Anweisungen in Vue

<<:  Detaillierte Erläuterung der MySQL-Remoteverbindungsberechtigung

>>:  Detaillierte Erläuterung der Installationsschritte der dekomprimierten MySQL-Version

Artikel empfehlen

Einführung in die Installation des Vim-Plugins unter Linux

Inhaltsverzeichnis Installieren Sie den Vim-Plugi...

Der Unterschied zwischen char und varchar in MySQL

CHAR- und VARCHAR-Typen sind ähnlich und untersch...

Drei Prinzipien effizienten Navigationsdesigns, die Webdesigner kennen müssen

Das Entwerfen der Navigation für eine Website ist...

Detaillierte Erläuterung der praktischen Anwendung der Centos7 ESXi6.7-Vorlage

1. Erstellen Sie ein Centos7.6-System und optimie...

So verwenden Sie JavaScript zum Implementieren von Sortieralgorithmen

Inhaltsverzeichnis Blasensortierung Auswahl Sorti...

So erstellen Sie schnell eine LAMP-Umgebung auf der CentOS-Plattform

Dieser Artikel beschreibt anhand eines Beispiels,...

Beispiele für Vorschaufunktionen für verschiedene Dateitypen in vue3

Inhaltsverzeichnis Vorwort 1. Vorschau der Office...

So legen Sie das Breitenattribut auf den Stil des Span-Tags fest

Wenn Sie das Breitenattribut direkt auf den Stil d...

Starten Sie eine lokale Kubernetes-Umgebung mit Kind und Docker

einführen Haben Sie schon einmal einen ganzen Tag...

Einführung in die neuen Funktionen von ECMAscript

Inhaltsverzeichnis 1. Standardwerte für Funktions...

JavaScript zum Erreichen eines Mouse-Tailing-Effekts

Mauseffekte erfordern die Verwendung von setTimeo...

So importieren und exportieren Sie Docker-Images

Dieser Artikel stellt den Import und Export von D...

Die v-for-Direktive in Vue vervollständigt die Listendarstellung

Inhaltsverzeichnis 1. Listendurchlauf 2. Die Roll...