Das Prinzip und die Implementierung der bidirektionalen Bindung in Vue2.x

Das Prinzip und die Implementierung der bidirektionalen Bindung in Vue2.x

Vue verwendet die Methode Object.defineProperty() um Daten zu kapern, und verwendet set und get, um das Lesen und Schreiben von Daten zu erkennen.

https://jsrun.net/RMIKp/embedded/all/light

Das MVVM-Framework umfasst hauptsächlich zwei Aspekte: Aktualisieren der Ansicht, wenn sich die Daten ändern, und Aktualisieren der Daten, wenn sich die Ansicht ändert.

Die Ansicht ändert und aktualisiert die Daten. Wenn es sich um ein Tag wie „Input“ handelt, können Sie oninput verwenden.

Um die Ansicht zu aktualisieren, wenn sich Daten ändern, können Sie die set Methode von Object.definProperty() verwenden, um Datenänderungen zu erkennen. Wenn sich die Daten ändern, wird diese Funktion ausgelöst und die Ansicht wird aktualisiert.

1. Implementierungsprozess

Nachdem wir nun wissen, wie die bidirektionale Bindung implementiert wird, müssen wir zunächst die Daten entführen und überwachen. Daher müssen wir eine Observer -Funktion einrichten, um Änderungen in allen Attributen zu überwachen.

Ändert sich die Eigenschaft, muss der Abonnenten watcher darüber informiert werden, um zu sehen, ob die Daten aktualisiert werden müssen. Bei mehreren Abonnenten wird ein Dep benötigt, um diese Abonnenten zu sammeln und sie dann einheitlich zwischen observer und watcher zu verwalten.

Außerdem ist eine Direktiveparser- compile erforderlich, um die Knoten und Attribute zu scannen und zu analysieren, die überwacht werden müssen.

Der Ablauf sieht also vermutlich so aus:

  • Implementieren Sie einen Observer , um alle Eigenschaften zu übernehmen und zu überwachen und Abonnenten zu benachrichtigen, wenn Änderungen auftreten.
  • Implementieren Sie einen Abonnenten Watcher . Wenn Sie eine Benachrichtigung über Eigenschaftsänderungen erhalten, führen Sie die entsprechende Funktion aus und aktualisieren Sie dann die Ansicht. Verwenden Sie Dep, um diese Watcher zu sammeln.
  • Implementieren Sie einen Parser- Compile , um die relevanten Anweisungen des Knotens zu scannen und zu analysieren, und initialisieren Sie den entsprechenden Abonnenten gemäß der Initialisierungsvorlage.

2. Zeigen Sie einen Beobachter an

Observer ist ein Datenlistener. Die Kernmethode besteht darin, Object.defineProperty() zu verwenden, um allen zu überwachenden Eigenschaften rekursiv setter und getter -Methoden hinzuzufügen.

var Bibliothek = {
  Buch1: {
    Name: "",
  },
  Buch2: "",
};
beobachten (Bibliothek);
library.book1.name = "vue authoritative guide"; // Der Eigenschaftsname wurde überwacht und der aktuelle Wert ist: "vue authoritative guide"
library.book2 = „Kein solches Buch“; // Das Attribut book2 wurde überwacht und der aktuelle Wert ist: „Kein solches Buch“

//Erkennungsfunktion für Daten hinzufügen defineReactive(data, key, val) {
  observe(val); // Alle Unterattribute rekursiv durchlaufen let dep = new Dep(); // Ein neues Dep erstellen
  Object.defineProperty(Daten, Schlüssel, {
    aufzählbar: wahr,
    konfigurierbar: true,
    bekomme: Funktion() {
      wenn (Dep.target) {
        // Bestimmen Sie, ob ein Abonnent hinzugefügt werden soll. Dies ist nur beim ersten Mal erforderlich und nicht beim nächsten Mal. Einzelheiten finden Sie in der Watcher-Funktion dep.addSub(Dep.target); // Einen Abonnenten hinzufügen }
      Rückgabewert;
    },
    setze: Funktion(neuerWert) {
      if (val == newVal) return; // zurück, wenn sich der Wert nicht geändert hat
      val = neuerWert;
      konsole.log(
        "Property" + key + " wurde überwacht und der aktuelle Wert ist: "" + newVal.toString() + """
      );
      dep.notify(); // Wenn sich die Daten ändern, alle Abonnenten benachrichtigen.
    },
  });
}

// Alle Eigenschaften des Monitoring-Objekts function observe(data) {
  wenn (!Daten || Datentyp !== "Objekt") {
    return; // Wenn es kein Objekt ist, returniere
  }
  Objekt.Schlüssel(Daten).fürJeden(Funktion(Schlüssel) {
    defineReactive(Daten, Schlüssel, Daten[Schlüssel]);
  });
}
// Dep ist für das Sammeln von Abonnenten und das Auslösen der Aktualisierungsfunktion verantwortlich, wenn sich die Eigenschaft ändert.
Funktion Dep() {
  dies.subs = {};
}
Dep.prototype = {
  addSub: Funktion(sub) {
    dies.subs.push(sub);
  },
  benachrichtigen: function() {
    Dies.subs.forEach((sub) => sub.update());
  },
};

Bei der Ideenanalyse muss ein Abonnenten-Dep vorhanden sein, das Abonnentennachrichten aufnehmen kann, zum Sammeln von Abonnenten und zum Ausführen der entsprechenden Aktualisierungsfunktion dient, wenn sich die Attribute ändern.

Aus dem Code geht hervor, dass das Hinzufügen des Abonnenten-Dep im getter Watcher bei seiner Initialisierung auslöst. Daher muss ermittelt werden, ob ein Abonnent erforderlich ist.

Wenn sich im setter die Daten ändern, werden alle Abonnenten benachrichtigt und die Abonnenten aktualisieren anschließend die entsprechenden Funktionen.

Bisher wurde ein relativ vollständiger Observer fertiggestellt. Als Nächstes beginnen wir mit der Entwicklung von Watcher.

3. Implementieren Sie Watcher

Der Abonnenten Watcher muss sich während der Initialisierung selbst zum Abonnenten-Dep hinzufügen. Wir wissen bereits, dass der Listener Observer die Watcher-Operation ist, die während des Gets ausgeführt wird. Daher müssen wir nur die entsprechende Get-Funktion auslösen, um die entsprechende Abonnenten-Operation hinzuzufügen, wenn Watcher initialisiert wird.

Wie lösen Sie also „Get“ aus? Da wir Object.defineProperty() bereits festgelegt haben, müssen wir nur den entsprechenden Eigenschaftswert abrufen, um es auszulösen.

Wir müssen den Abonnenten nur auf Dep.target zwischenspeichern, wenn der Abonnenten-Watcher initialisiert wird, und ihn nach erfolgreichem Hinzufügen entfernen.

Funktion Watcher(vm, exp, cb) {
  dies.cb = cb;
  dies.vm = vm;
  dies.exp = exp;
  this.value = this.get(); // Fügen Sie sich selbst zur Operation des Abonnenten hinzu}

Watcher.Prototyp = {
  aktualisieren: Funktion() {
    dies.laufen();
  },
  ausführen: function() {
    var-Wert = this.vm.data[this.exp];
    var alterWert = dieser.Wert;
    wenn (Wert !== alterWert) {
      dieser.Wert = Wert;
      this.cb.call(this.vm, Wert, alterWert);
    }
  },
  bekomme: Funktion() {
    Dep.target = this; // Cache selbst, um zu bestimmen, ob ein Watcher hinzugefügt werden soll.
    var value = this.vm.data[this.exp]; // Erzwinge die Ausführung der Get-Funktion im Listener Dep.target = null; // Befreie dich selbst return value;
  },
};

Bisher ist das einfache Watcher -Design abgeschlossen. Durch die Verknüpfung Observer und Watcher kann anschließend eine einfache bidirektionale Bindung implementiert werden.

Da die Parser- Compile noch nicht entworfen wurde, können die Vorlagedaten zunächst fest codiert werden.

Konvertieren Sie den Code in einen ES6-Konstruktor und zeigen Sie eine Vorschau an.

https://jsrun.net/8SIKp/embed...

Da dieser Code keinen Compiler implementiert, sondern die gebundenen Variablen direkt übergibt, legen wir zur Bindung nur Daten ( name ) auf einem Knoten fest und führen dann new MyVue auf der Seite aus, um eine bidirektionale Bindung zu erreichen.

Und nehmen Sie die Änderungen nach zwei Sekunden vor. Sie können sehen, dass sich auch die Seite geändert hat.

// MyVue
ProxyKeys(Schlüssel) {
    var selbst = dies;
    Object.defineProperty(dieser, Schlüssel, {
        aufzählbar: falsch,
        konfigurierbar: true,
        erhalten: Funktion ProxyGetter() {
            gibt self.data[Schlüssel] zurück;
        },
        set: Funktion ProxySetter(neuerWert) {
            self.data[Schlüssel] = neuerWert;
        }
    });
}

Der Zweck des obigen Codes besteht darin, den Schlüssel von this.data hierher zu proxyen, sodass ich this.xx problemlos verwenden kann, um this.data.xx zu erhalten.

4. Implementieren Sie Compile

Obwohl oben eine bidirektionale Datenbindung implementiert ist, werden die DOM-Knoten während des gesamten Prozesses nicht analysiert, sondern fest ersetzt. Daher ist ein Parser erforderlich, um die Daten zu analysieren und zu binden.

Implementierungsschritte der Parser compile :

  • Analysieren Sie die Vorlagenanweisungen, ersetzen Sie die Vorlagendaten und initialisieren Sie die Ansicht.
  • Binden Sie die entsprechende Update-Funktion an den in der Vorlage angegebenen Knoten und initialisieren Sie den entsprechenden Abonnenten.

Um die Vorlage zu analysieren, müssen Sie zuerst die DOM-Daten analysieren und dann die entsprechenden Anweisungen für die DOM-Elemente verarbeiten. Daher ist der gesamte DOM-Vorgang relativ häufig. Sie können ein neues Fragment erstellen und das erforderliche analysierte DOM zur Verarbeitung im fragment speichern.

Funktion nodeToFragment(el) {
  var fragment = document.createDocumentFragment();
  var Kind = el.erstesKind;
  während (Kind) {
    // Verschiebe das Dom-Element in das Fragment fragment.appendChild(child);
    Kind = el.erstesKind;
  }
  Fragment zurückgeben;
}

Als Nächstes müssen Sie jeden Knoten durchlaufen und eine spezielle Verarbeitung an den Knoten durchführen, die relevante Anweisungen und Vorlagensyntax enthalten. Führen Sie zunächst die einfachste Vorlagensyntaxverarbeitung durch und verwenden Sie reguläre Ausdrücke, um die Syntax in der Form „{{variable}}“ zu analysieren.

Funktion KompilierenElement (el) {
    var childNodes = el.childNodes;
    var selbst = dies;
    [].slice.call(childNodes).forEach(Funktion(Knoten) {
        var reg = /\{\{(.*)\}\}/; // entspricht {{xx}}
        var text = node.textinhalt;
        if (self.isTextNode(node) && reg.test(text)) { // Bestimme, ob es sich um eine Anweisung dieser Form handelt {{}} self.compileText(node, reg.exec(text)[1]);
        }
        wenn (node.childNodes && node.childNodes.length) {
            self.compileElement(node); //Weiter mit dem rekursiven Durchlaufen der untergeordneten Knoten}
    });
},
Funktion KompilierenText (Knoten, Ausdruck) {
    var selbst = dies;
    var initText = this.vm[exp];
    updateText(node, initText); // Initialisiere die initialisierten Daten in der Ansicht new Watcher(this.vm, exp, function (value) { // Generiere einen Abonnenten und binde die Update-Funktion self.updateText(node, value);
    });
},
Funktion updateText (Knoten, Wert) {
    node.textContent = Typ des Wertes == ‚undefiniert‘?‘‘: Wert;
}

Rufen Sie nach dem Abrufen des äußersten Knotens compileElement auf, um alle untergeordneten Knoten zu beurteilen. Wenn der Knoten ein Textknoten ist und der Anweisung in Form von {{}} entspricht, kompilieren Sie ihn und initialisieren Sie die entsprechenden Parameter.

Anschließend müssen Sie für die aktuellen Parameter einen entsprechenden Abonnenten der Aktualisierungsfunktion generieren, um bei einer Datenänderung das entsprechende DOM zu aktualisieren.

Damit sind die drei Prozesse Parsen, Initialisieren und Kompilieren abgeschlossen.

Ändern Sie als Nächstes myVue, um Vorlagenvariablen für die bidirektionale Datenbindung zu verwenden.

https://jsrun.net/K4IKp/embed...

5. Fügen Sie Analyseereignisse hinzu

Nach dem Hinzufügen von compile ist eine bidirektionale Datenbindung grundsätzlich abgeschlossen. Der nächste Schritt besteht darin, weitere Anweisungen zum Parsen und Kompilieren in Compile hinzuzufügen, z. B. v-model , v-on , v-bind usw.

Fügen Sie ein V-Modell und eine V-On-Analyse hinzu:

Funktion Kompilieren(Knoten) {
  var nodeAttrs = node.attributes;
  var selbst = dies;
  Array.prototype.forEach.call(nodeAttrs, Funktion(attr) {
    var attrName = attr.name;
    wenn (istDirektive(attrName)) {
      var exp = attr.Wert;
      var dir = attrName.substring(2);
      if (isEventDirective(dir)) {
        // Ereignisanweisung self.compileEvent(node, self.vm, exp, dir);
      } anders {
        // v-model-Direktive self.compileModel(node, self.vm, exp, dir);
      }
      node.removeAttribute(attrName); // Analyse abgeschlossen, Attribut entfernen}
  });
}
// v-Direktive-Analysefunktion isDirective(attr) {
  return attr.indexOf("v-") == 0;
}
// ein: Direktive-Analysefunktion isEventDirective(dir) {
  return dir.indexOf("on:") === 0;
}

Die obige compile wird verwendet, um alle Knotenattribute des aktuellen dom zu durchlaufen und dann zu bestimmen, ob das Attribut ein Direktivattribut ist. Wenn dies der Fall ist, wird die entsprechende Verarbeitung durchgeführt (Ereignisse werden auf Ereignisse überwacht, Daten werden auf Daten überwacht ...)

6. Vollversion von myVue

Fügen Sie in MyVue eine mounted Methode hinzu und führen Sie sie aus, wenn alle Vorgänge abgeschlossen sind.

Klasse MyVue {
  Konstruktor(Optionen) {
    var selbst = dies;
    diese.Daten = Optionen.Daten;
    diese.Methoden = Optionen.Methoden;
    Object.keys(diese.Daten).forEach(Funktion(Schlüssel) {
      self.proxyKeys(Schlüssel);
    });
    beobachte(diese.Daten);
    neues Kompilieren(options.el, this);
    options.mounted.call(this); //Führen Sie die gemountete Funktion aus, nachdem alles erledigt ist}
  ProxyKeys(Schlüssel) {
    // Proxy this.data-Eigenschaft an diese Variable self = this;
    Object.defineProperty(dieser, Schlüssel, {
      aufzählbar: falsch,
      konfigurierbar: true,
      erhalten: Funktion Getter () {
        gibt self.data[Schlüssel] zurück;
      },
      set: Funktion Setter(neuerWert) {
        self.data[Schlüssel] = neuerWert;
      },
    });
  }
}

Dann kannst Du es testen.

https://jsrun.net/Y4IKp/embed...

Fassen wir den Vorgang zusammen. Wenn Sie sich dieses Diagramm noch einmal ansehen, ist es jetzt viel klarer.

Sie können die Codeadresse anzeigen: Vue2.x-Zwei-Wege-Bindungsprinzip und -Implementierung

Dies ist das Ende dieses Artikels über das Zwei-Wege-Bindungsprinzip und die Implementierung von Vue2.x Weitere relevante Inhalte zum Zwei-Wege-Bindungsprinzip von Vue-Daten finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Beispielcode einer benutzerdefinierten Vue-Komponente zur Implementierung bidirektionaler V-Model-Bindungsdaten
  • Implementierung der bidirektionalen Bindung von übergeordneten und untergeordneten Komponentendaten im Front-End-Framework Vue
  • Eine kurze Diskussion über das Prinzip des bidirektionalen Ereignisbindungs-V-Modells von Vue
  • Verwenden von js zum Implementieren der bidirektionalen Bindungsfunktion von Daten in Vue2.0
  • So implementieren Sie eine bidirektionale Bindungsfunktion in vue.js mit reinem JS
  • Detaillierte Erläuterung der bidirektionalen Bindung von Vue

<<:  Analyse der Prinzipien der MySQL Slow Query-bezogenen Parameter

>>:  Eine kurze Diskussion über die MySQL-Optimierungslösung für große Tabellen

Artikel empfehlen

So führen Sie SCSS in ein React-Projekt ein

Laden Sie zuerst die Abhängigkeiten herunter Garn...

Achten Sie bei der Webseitenerstellung auf die Verwendung von HTML-Tags

Dieser Artikel stellt einige Aspekte von HTML-Tag...

Beispielerklärung von MySQL-Fremdschlüsseleinschränkungen

Die Fremdschlüsseleinschränkung von MySQL dient z...

Eine kurze Diskussion darüber, wie man Div und Tabelle auswählt und kombiniert

Das Seitenlayout war mir schon immer ein Anliegen...

PNG-Alpha-Transparenz in IE6 (vollständige Sammlung)

Viele Leute sagen, dass IE6 PNG-Transparenz nicht...

Verwendung des offiziellen MySQL-Exporttools mysqlpump

Inhaltsverzeichnis Einführung Anweisungen Tatsäch...

Neue Funktionen in MySQL 8.0: Hash Join

Das MySQL-Entwicklungsteam hat am 14. Oktober 201...

Beispiel für die Verwendung von Dockerfile zum Erstellen eines Nginx-Images

Einführung in Dockerfile Docker kann automatisch ...

Tutorial zur manuellen Installation und Konfiguration von mysql8.0.11 winx64

Lassen Sie mich zunächst über meinen Alltag sprec...

Detaillierte Erläuterung der MySQL-Fremdschlüsseleinschränkungen

Amtliche Dokumentation: https://dev.mysql.com/doc...