Implementierungsmethode für die bidirektionale Bindung von Vue-Daten

Implementierungsmethode für die bidirektionale Bindung von Vue-Daten

1. Einleitung

Dieser Artikel ist für Anfänger geeignet, die den Vue-Quellcode lernen. Nach der Lektüre haben Sie ein allgemeines Verständnis des Prinzips der bidirektionalen Datenbindung in Vue und verstehen die drei Hauptrollen von Observer, Compile und Wathcer (wie in der folgenden Abbildung dargestellt) und ihre Funktionen.

In diesem Artikel werden Sie Schritt für Schritt durch die Implementierung einer einfachen Version der bidirektionalen Datenbindung geführt. In jedem Schritt wird das in diesem Schritt zu lösende Problem und der Grund für die Art und Weise, wie der Code geschrieben wird, detailliert analysiert. Daher hoffe ich, dass Sie nach dem Lesen dieses Artikels selbst eine einfache Version der bidirektionalen Datenbindung implementieren können.

2. Code-Implementierung

2.1 Zweckanalyse

Der mit diesem Artikel zu erzielende Effekt ist in der folgenden Abbildung dargestellt:

Die in diesem Artikel verwendeten HTML- und JS-Hauptcodes sind wie folgt:

<div id="app">
  <h1 v-text="msg"></h1>
  <Eingabetyp="Text" v-Modell="Nachricht">
  <div>
    <h1 v-text="msg2"></h1>
    <Eingabetyp="text" v-modell="msg2">
  </div>
</div>
lass vm = neues Vue({
    el: "#app",
    Daten: {
      Nachricht: "Hallo Welt",
      msg2: „hallo xiaofei“
    }
  })

Dazu gehen wir in drei Schritten vor:

  • Schritt 1: Synchronisieren Sie die Daten in den Daten mit der Seite, um die Initialisierung von M ==> V zu erreichen;
  • Schritt 2: Wenn ein Wert in das Eingabefeld eingegeben wird, wird der neue Wert mit den Daten synchronisiert, um die Bindung von V ==> M zu erreichen.
  • Schritt 3: Wenn die Daten aktualisiert werden, wird eine Seitenänderung ausgelöst, wodurch die Bindung von M ==> V realisiert wird.

2.2 Implementierungsprozess

2.2.1 Zugangscode

Zuerst müssen wir eine Vue-Klasse erstellen, die ein Optionsobjekt empfängt. Gleichzeitig müssen wir die gültigen Informationen im Optionsobjekt speichern.

Dann haben wir drei Hauptmodule: Observer, Compile und Wathcer. Unter ihnen wird Observer zum Daten-Hijacking verwendet, Compile wird zum Parsen von Elementen verwendet und Wathcer ist ein Beobachter. Sie können den folgenden Code schreiben: (Es ist nicht erforderlich, die drei Konzepte Observer, Compile und Wathcer im Detail zu studieren, da sie später ausführlich erläutert werden.)

Klasse Vue {
    // Empfange das übergebene Objekt Konstruktor(Optionen) {
      // Gültige Informationen speichern this.$el = document.querySelector(options.el);
      dies.$data = Optionen.data;

      //Container: {Attribut 1: [wathcer1, wathcer2...], Attribut 2: [...]}, wird zum Speichern jedes Attributbeobachters verwendet. $watcher = {};

      // Elemente analysieren: Implementieren von Compile
      this.compile(this.$el); // Um ​​das Element zu analysieren, müssen Sie das Element übergeben in // Daten kapern: Observer implementieren
      this.observe(this.$data); // Um ​​Daten zu kapern, müssen Sie die Daten übergeben}
    kompilieren() {}
    beobachten() {}
  }

2.2.2 Seiteninitialisierung

In diesem Schritt müssen wir die Seite initialisieren, das heißt, die V-Text- und V-Model-Anweisungen analysieren und die Daten in Daten auf der Seite rendern.

Der Schlüssel zu diesem Schritt besteht darin, die Kompilierungsmethode zu implementieren. Wie also wird das el-Element analysiert? Die Idee ist folgende:

  • Zuerst müssen wir alle untergeordneten Knoten unter el abrufen und dann diese untergeordneten Knoten durchlaufen. Wenn die untergeordneten Knoten untergeordnete Knoten haben, müssen wir die Idee der Rekursion verwenden.
  • Durchlaufen Sie die untergeordneten Knoten, um alle Elemente mit Anweisungen zu finden, und rendern Sie die entsprechenden Daten auf der Seite.

Der Code lautet wie folgt: (sehen Sie sich hauptsächlich den Kompilierungsteil an)

Klasse Vue {
    // Empfange das übergebene Objekt Konstruktor(Optionen) {
      // Nützliche Informationen erhalten this.$el = document.querySelector(options.el);
      dies.$data = Optionen.data;

      // Container: {attribute1: [wathcer1, wathcer2...], attribute2: [...]}
      dies.$watcher = {};

      // 2. Elemente analysieren: Implementieren von Compile
      this.compile(this.$el); // Um ​​das Element zu parsen, musst du das Element übergeben in // 3. Daten kapern: Observer implementieren
      this.observe(this.$data); // Um ​​Daten zu kapern, müssen Sie die Daten übergeben}
    kompilieren(el) {
      // Analysieren Sie jeden untergeordneten Knoten unter dem Element, um el.children zu erhalten.
      // Hinweis: children gibt einen Elementsatz zurück, childNodes gibt einen Knotensatz zurück let nodes = el.children;

      // Analysiere die Anweisungen für jeden untergeordneten Knoten for (var i = 0, length = nodes.length; i < length; i++) {
        sei Knoten = Knoten[i];
        // Wenn der aktuelle Knoten untergeordnete Elemente hat, den Knoten rekursiv analysieren if(node.children){
          dies.kompilieren(Knoten);
        }
        // Elemente mit der v-text-Direktive analysieren if (node.hasAttribute("v-text")) {
          let attrVal = node.getAttribute("v-text");
          node.textContent = this.$data[attrVal]; // Seite rendern}
        // Elemente mit v-model-Direktiven analysieren if (node.hasAttribute("v-model")) {
          let attrVal = node.getAttribute("v-Modell");
          Knoten.Wert = dies.$data[attrVal];
        }
      }
    }
    beobachten(Daten) {}
  }

Auf diese Weise haben wir die Initialisierung der Seite erreicht.

2.2.3 Ansichten beeinflussen Daten

Da die Eingabe über eine V-Modell-Anweisung verfügt, müssen wir eine solche Funktion implementieren: Wenn Zeichen in das Eingabefeld eingegeben werden, ändern sich die in den Daten gebundenen Daten entsprechend.

Wir können ein Eingabeereignis an das Eingabeelement binden. Die Auswirkung des Ereignisses besteht darin, die entsprechenden Daten in Daten in den Wert in Eingabe zu ändern.

Der Implementierungscode dieses Teils ist relativ einfach. Sie können ihn verstehen, indem Sie sich die markierte Stelle ansehen. Der Code lautet wie folgt:

Klasse Vue {
    Konstruktor(Optionen) {
      dies.$el = document.querySelector(options.el);
      dies.$data = Optionen.data;
      
      dies.$watcher = {};  

      dies.kompilieren(dies.$el);

      dies.beobachten(diese.$daten);
    }
    kompilieren(el) {
      lass Knoten = el.children;

      für (var i = 0, Länge = Knoten.Länge; i < Länge; i++) {
        sei Knoten = Knoten[i];
        wenn(Knoten.Kinder){
          dies.kompilieren(Knoten);
        }
        wenn (node.hasAttribute("v-text")) {
          let attrVal = node.getAttribute("v-text");
          node.textContent = dies.$data[attrVal];
        }
        wenn (node.hasAttribute("v-model")) {
          let attrVal = node.getAttribute("v-Modell");
          Knoten.Wert = dies.$data[attrVal];
          // Schau mal hier! ! Nur noch drei Codezeilen! !
          node.addEventListener("Eingabe", (ev)=>{
            dies.$data[attrVal] = ev.target.value;
            // Sie können versuchen, es hier auszuführen: console.log(this.$data),
            // Sie können sehen, dass sich jedes Mal, wenn Sie Text in das Eingabefeld eingeben, auch der Nachrichtenwert in den Daten ändert})
        }
      }
    }
    beobachten(Daten) {}
  }

2.2.4 Datenauswirkungsansicht

Bisher haben wir erreicht, dass die Daten in den Daten automatisch aktualisiert werden, wenn wir Zeichen in das Eingabefeld eingeben.

Die Hauptaufgabe dieses Abschnitts besteht darin, dass bei einer Aktualisierung der Daten die an die Daten gebundenen Elemente automatisch die Ansicht auf der Seite aktualisieren. Die konkreten Vorstellungen sind wie folgt:

1) Wir implementieren eine Watcher-Klasse, die über eine Update-Methode zum Aktualisieren der Seite verfügt. Der Beobachtercode lautet wie folgt:

Klasse Watcher{
    Konstruktor(Knoten, aktualisiertesAttr, vm, Ausdruck){
      //Speichere die übergebenen Werte. Diese Werte werden beim Rendern der Seite verwendet. this.node = node;
      dies.updatedAttr = updatedAttr;
      dies.vm = vm;
      dieser.Ausdruck = Ausdruck;
      dies.update();
    }
    aktualisieren(){
      dieser.Knoten[dieses.updatedAttr] = diese.vm.$data[dieser.Ausdruck];
    }
  }

2) Überlegen Sie, welchen Daten wir Beobachter hinzufügen sollten? Wann sollten den Daten Beobachter hinzugefügt werden?

Beim Parsen des Elements, wenn die Anweisungen für V-Text und V-Modell analysiert werden, bedeutet dies, dass dieses Element in beide Richtungen an die Daten gebunden werden muss. Daher fügen wir dem Container zu diesem Zeitpunkt einen Beobachter hinzu. Wir müssen eine Datenstruktur wie diese verwenden: {Attribut 1: [wathcer1, wathcer2...], Attribut 2: [...]}. Wenn das nicht ganz klar ist, können Sie die folgende Abbildung sehen:

Sie können sehen, dass in der Vue-Instanz ein $watcher-Objekt vorhanden ist. Jedes Attribut von $watcher entspricht den Daten, die gebunden werden müssen, und der Wert ist ein Array, in dem die Beobachter gespeichert werden, die die Daten beobachtet haben. (Hinweis: Der Vue-Quellcode erstellt speziell eine Klasse namens Dep, die dem hier erwähnten Array entspricht. Dieser Artikel ist eine vereinfachte Version, daher werde ich ihn nicht im Detail vorstellen.)

3) Daten kapern: Verwenden Sie den Getter und Setter der Accessor-Eigenschaft des Objekts, um eine Aktion auszulösen, wenn die Daten aktualisiert werden. Der Hauptzweck dieser Aktion besteht darin, allen Beobachtern, die die Daten beobachtet haben, die Ausführung der Aktualisierungsmethode zu ermöglichen.

Um zusammenzufassen, was wir in diesem Abschnitt tun müssen:

  1. Implementieren Sie eine Watcher-Klasse;
  2. Fügen Sie beim Parsen von Anweisungen (d. h. in der Kompilierungsmethode) Beobachter hinzu.
  3. Implementieren Sie Datenentführung (implementieren Sie die Beobachtungsmethode).

Der vollständige Code lautet wie folgt:

  Klasse Vue {
    // Empfange das übergebene Objekt Konstruktor(Optionen) {
      // Nützliche Informationen erhalten this.$el = document.querySelector(options.el);
      dies.$data = Optionen.data;

      // Container: {attribute1: [wathcer1, wathcer2...], attribute2: [...]}
      dies.$watcher = {};

      // Elemente analysieren: Implementieren von Compile
      this.compile(this.$el); // Um ​​das Element zu analysieren, müssen Sie das Element übergeben in // Daten kapern: Observer implementieren
      this.observe(this.$data); // Um ​​Daten zu kapern, müssen Sie die Daten übergeben}
    kompilieren(el) {
      // Analysieren Sie jeden untergeordneten Knoten unter dem Element, um el.children zu erhalten.
      // Erweiterung: children gibt einen Elementsatz zurück, childNodes gibt einen Knotensatz zurück let nodes = el.children;

      // Analysiere die Anweisungen für jeden untergeordneten Knoten for (var i = 0, length = nodes.length; i < length; i++) {
        sei Knoten = Knoten[i];
        // Wenn der aktuelle Knoten untergeordnete Elemente hat, den Knoten rekursiv analysieren, if (node.children) {
          dies.kompilieren(Knoten);
        }
        wenn (node.hasAttribute("v-text")) {
          let attrVal = node.getAttribute("v-text");
          // node.textContent = this.$data[attrVal]; 
          // Der Watcher ruft bei der Instanziierung „update“ auf und ersetzt diese Codezeile/**
           * Stellen Sie sich vor, welche Daten Wathcer zum Aktualisieren von Knotendaten verwenden muss? 
           * egpinnerHTML = vm.$data[msg]
           * Die zu übergebenden Parameter sind also: aktueller Knoten, zu aktualisierende Knotenattribute, Vue-Instanz, gebundene Datenattribute*/
          // Beobachter zum Container hinzufügen: {msg1: [Watcher, Watcher...], msg2: [...]}
          wenn (!this.$watcher[attrVal]) {
            dies.$watcher[attrVal] = [];
          }
          dies.$watcher[attrVal].push(neuer Watcher(Knoten, "innerHTML", dies, attrVal))
        }
        wenn (node.hasAttribute("v-model")) {
          let attrVal = node.getAttribute("v-Modell");
          Knoten.Wert = dies.$data[attrVal];

          node.addEventListener("Eingabe", (ev) => {
            dies.$data[attrVal] = ev.target.value;
          })

          wenn (!this.$watcher[attrVal]) {
            dies.$watcher[attrVal] = [];
          }
          // Anders als das oben verwendete innerHTML verwendet die Eingabe hier das Wertattribut this.$watcher[attrVal].push(new Watcher(node, "value", this, attrVal))
        }
      }
    }
    beobachten(Daten) {
      Objekt.Schlüssel(Daten).fürJeden((Schlüssel) => {
        let val = data[key]; // Dieser Wert wird immer im Speicher gespeichert. Jedes Mal, wenn Sie auf data[key] zugreifen, greifen Sie auf diesen Wert zu
        Object.defineProperty(Daten, Schlüssel, {
          erhalten() {
            return val; // Du kannst data[key] hier nicht direkt zurückgeben, sonst gerät es in eine Endlosschleife},
          setze(neuerWert) {
            wenn (Wert !== neuerWert) {
              val = newVal; // Ebenso kann data[key] hier nicht direkt gesetzt werden, was zu einer Endlosschleife führen würde this.$watcher[key].forEach((w) => {
                w.update();
              })
            }
          }
        })
      })
    }
  }

  Klasse Watcher {
    Konstruktor(Knoten, aktualisiertesAttr, vm, Ausdruck) {
      //Den übergebenen Wert speichern this.node = node;
      dies.updatedAttr = updatedAttr;
      dies.vm = vm;
      dieser.Ausdruck = Ausdruck;
      dies.update();
    }
    aktualisieren() {
      dieser.Knoten[dieses.updatedAttr] = diese.vm.$data[dieser.Ausdruck];
    }
  }

  lass vm = neues Vue({
    el: "#app",
    Daten: {
      Nachricht: "Hallo Welt",
      msg2: „hallo xiaofei“
    }
  })

An diesem Punkt ist der Code vollständig.

3. Zukunftspläne

Verwenden Sie das Wissen über Entwurfsmuster, um die Probleme im obigen Quellcode zu analysieren und ihn mit dem Vue-Quellcode zu vergleichen. Dies gilt als Analyse des Vue-Quellcodes.

Oben finden Sie den detaillierten Inhalt der Implementierungsmethode der bidirektionalen Vue-Datenbindung. Weitere Informationen zur bidirektionalen Vue-Datenbindung finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Detaillierte Erläuterung des Implementierungsprinzips der bidirektionalen Datenbindung von Vue2.0/3.0
  • Analyse des Problems des Datenverlusts durch erzwungene Aktualisierung von Vuex
  • Wie verfolgt Vue Datenänderungen?
  • Vue + Canvas realisiert den Effekt der Aktualisierung des Wasserfalldiagramms von oben nach unten in Echtzeit (ähnlich wie QT).
  • Lösung für das Vue-Datenzuweisungsproblem
  • Vue setzt die Daten auf ihren ursprünglichen Zustand zurück
  • Analyse und Lösung von Datenverlusten während der Wertübertragung von Vue-Komponenten
  • SpringBoot + Vue realisiert die Funktion zum Hinzufügen von Daten
  • Beispiel für handschriftliches Vue2.0-Daten-Hijacking
  • Vermeiden Sie den Missbrauch zum Lesen von Daten in Vue
  • Entwerfen Sie einen Datensammler mit Vue

<<:  Detaillierte Erläuterung des Selinux-Grundkonfigurationstutorials unter Linux

>>:  Beispiel zum Erstellen eines lokalen Benutzers in MySQL und Erteilen von Datenbankberechtigungen

Artikel empfehlen

Allgemeiner HTML-Seitenstil (empfohlen)

Wie unten dargestellt: XML/HTML-CodeInhalt in die...

So fügen Sie einer großen MySQL-Tabelle eine Spalte hinzu

Die Frage wird hier zitiert: https://www.zhihu.co...

25 Vue-Tipps, die Sie kennen müssen

Inhaltsverzeichnis 1. Beschränken Sie Requisiten ...

Fähigkeiten zur Seiten-Refaktorierung - Inhalt

Genug des Smalltalks <br />Basierend auf de...

Codebeispiele für die Sicherung mehrerer MySQL-Datenbanken

In diesem Artikel werden hauptsächlich Codebeispi...

So verwenden Sie „not in“ zur Optimierung von MySql

Als ich kürzlich in einem Projekt eine Auswahlabf...

Detaillierte Erklärung der Kartenüberlagerung in OpenLayers6

1. Overlay-Übersicht Overlay bedeutet Überlagerun...

Lösung für das Problem des MySQL-Threads beim Öffnen von Tabellen

Problembeschreibung Vor kurzem gab es einen MySQL...

Flammenanimation mit CSS3 umgesetzt

Ergebnisse erzielen Implementierungscode html <...

Erläuterung des Arbeitsmechanismus von Namenode und SecondaryNameNode in Hadoop

1) Prozess 2) FSImage und Bearbeitungen Nodenode ...

Detaillierte Erklärung von MySQL-Transaktionen und MySQL-Protokollen

Transaktionale Merkmale 1. Atomarität: Nach dem S...

Vier Möglichkeiten zum Vergleichen von JavaScript-Objekten

Inhaltsverzeichnis Vorwort Referenzvergleich Manu...

Beispiel zur Erhöhung des Swap-Speichers im CentOS7-System

Vorwort Swap ist eine spezielle Datei (oder Parti...

Detaillierte Analyse des temporären JDBC- und MySQL-Tablespace

Hintergrund Temporäre Tablespaces werden verwende...