Eine kurze Analyse der grundlegenden Implementierung von Vue-Erkennungsdatenänderungen

Eine kurze Analyse der grundlegenden Implementierung von Vue-Erkennungsdatenänderungen

1. Objektänderungserkennung

Als nächstes simulieren wir die Logik zur Erkennung von Datenänderungen.

Lassen Sie mich betonen, was wir tun werden: Die Außenwelt über Datenänderungen benachrichtigen (die Außenwelt führt dann einige ihrer eigenen logischen Verarbeitungsvorgänge durch, beispielsweise das erneute Rendern der Ansicht).

Bevor wir mit dem Codieren beginnen, müssen wir zunächst die folgenden Fragen beantworten:

1. Wie erkennt man Veränderungen an Objekten?

  • Verwenden Sie Object.defineProperty(). Der Getter wird beim Lesen von Daten und der Setter beim Ändern von Daten ausgelöst.
  • Nur durch die Erkennung von Änderungen an Objekten können Benachrichtigungen bei Datenänderungen ausgegeben werden.

2. Wen benachrichtigen wir bei Datenänderungen?

  • Benachrichtigen Sie, wo die Daten verwendet werden. Die Daten können im Template oder in vm.$watch() verwendet werden. Das Verhalten ist an verschiedenen Stellen unterschiedlich, hier muss beispielsweise das Template gerendert werden und dort muss eine andere Logik ausgeführt werden. Abstrahieren Sie also einfach eine Klasse. Wenn sich die Daten ändern, benachrichtigen Sie es, und dann werden auch andere Stellen benachrichtigt.
  • Diese Klasse heißt Watcher. Es ist nur ein Vermittler.

3. Auf wen kann man sich verlassen?

  • Wen Sie benachrichtigen, hängt von Ihnen ab, das heißt von Watcher.

4. Wann werden Sie benachrichtigt?

  • Beim Ändern von Daten. Das heißt, Benachrichtigung im Setter

5. Wann sollen Abhängigkeiten erfasst werden?

  • Denn wir müssen die Stellen informieren, an denen die Daten genutzt werden. Um Daten nutzen zu können, müssen wir die Daten lesen. Wir können sie beim Lesen der Daten sammeln, also im Getter sammeln.

6. Wo werden die Daten erhoben?

  • Sie können in jedem Attribut ein Array definieren und alle mit dem Attribut verbundenen Abhängigkeiten darin einfügen.

Der Code lautet wie folgt (kann direkt ausgeführt werden):

// Globale Variablen zum Speichern von Abhängigkeiten let globalData = undefined;

// Daten in responsive Funktion umwandeln defineReactive (obj, key, val) {
    // Abhängigkeitsliste let dependList = []
    Objekt.defineProperty(Objekt, Schlüssel, {
      aufzählbar: wahr,
      konfigurierbar: true,
      erhalten: Funktion () {
        // Abhängigkeiten sammeln (Watcher)
        globalData und dependList.push(globalData)
        Rückgabewert
      },
      set: Funktion reactiveSetter (newVal) {
        wenn(Wert === neuerWert){
            zurückkehren
        }
        // Benachrichtigungsabhängigkeiten (Watcher)
        dependList.fürJeden(w => {
            w.update(neuerWert, Wert)
        })
        val = neuerWert
      }
    });
}

// Hängt von der Klasse Watcher{ ab.
    Konstruktor(Daten, Schlüssel, Rückruf){
        diese.daten = Daten;
        dieser.Schlüssel = Schlüssel;
        this.callback = Rückruf;
        dies.val = dies.get();
    }
    // Dieser Code kann sich selbst zur Abhängigkeitsliste hinzufügen get(){
        //Abhängigkeiten in globalData speichern
        globalData = dies;
        // Beim Lesen von Daten Abhängigkeiten sammeln let value = this.data[this.key]
        globalData = undefiniert
        Rückgabewert;
    }
    // Benachrichtigung erhalten, wenn sich Daten ändern, und dann die Außenwelt benachrichtigen update(newVal, oldVal){
        this.callback(neuerWert, alterWert)
    }
}

/* Das Folgende ist der Testcode */
lass Daten = {};
// Das Namensattribut responsiv machen defineReactive(data, 'age', '88')
// Wenn sich das Datenalter ändert, wird der Watcher benachrichtigt, und anschließend benachrichtigt der Watcher die Außenwelt new Watcher(data, 'age', (newVal, oldVal) => {
    console.log(`Außenwelt: newVal = ${newVal}; oldVal = ${oldVal}`)
})

data.age -= 1 // Konsolenausgabe: Extern: newVal = 87; oldVal = 88

Führen Sie die Ausführung data.age -= 1 in der Konsole weiter aus.外界:newVal = 86 ; oldVal = 87 .

Anbei ein Beziehungsdiagramm zwischen Data, defineReactive, dependList, Watcher und der Außenwelt.

Konvertieren Sie die Daten zunächst mit der Methode defineReactive() ( defineReactive(data, 'age', '88') ) in responsive Daten.

Die Außenwelt liest Daten über Watcher ( let value = this.data[this.key] ), der Datengetter wird ausgelöst und dann sammelt Watcher Daten über globalData.

Wenn die Daten geändert werden ( data.age -= 1 ), wird der Setter ausgelöst, die Abhängigkeit (dependList) wird benachrichtigt, die Abhängigkeit benachrichtigt den Watcher ( w.update(newVal, val) ) und schließlich benachrichtigt der Watcher die Außenwelt.

2. Fragen zum Objekt

Denken Sie darüber nach: Wird im obigen Beispiel die Außenwelt benachrichtigt, wenn delete data.age fortgefahren wird?

Gewohnheit. Weil der Setter nicht ausgelöst wird. Bitte lesen Sie weiter:

<!DOCTYPE html>
<html lang="de">
<Kopf>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=Gerätebreite, Anfangsmaßstab=1.0">
    <title>Dokument</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</Kopf>
<Text>
    <div id='App'>
        <Abschnitt>
            {{ p1.name }}
            {{ p1.age }}
        </Abschnitt>
    </div>
<Skript>
const app = new Vue({
    el: '#app',
    Daten: {
        p1: {
            Name: 'ph',
            Alter: 18
        }
    }
})
</Skript>
</body>
</html>

Nach dem Ausführen wird auf der Seite ph 18 angezeigt. Wir wissen, dass die Ansicht neu gerendert wird, wenn die Daten geändert werden. Daher führen wir delete app.p1.name in der Konsole aus und stellen fest, dass sich die Seite nicht geändert hat. Dies entspricht der Ausführung von delete data.age im obigen Beispiel. Der Setter wird nicht ausgelöst und die Außenwelt wird nicht benachrichtigt.

Um dieses Problem zu lösen, bietet Vue zwei APIs (die später vorgestellt werden): vm.$set und vm.$delete.

Wenn Sie mit der Ausführung app.$delete(app.p1, 'age') fortfahren, werden Sie feststellen, dass die Seite keine Informationen enthält (das Namensattribut wurde mit „delete“ gelöscht, aber damals nicht erneut gerendert).

Hinweis : Wenn hier app.p1.sex = 'man' ausgeführt wird, wird der Ort, an dem die Daten p1 verwendet werden, nicht benachrichtigt. Dieses Problem kann durch vm.$set gelöst werden.

Array-Änderungserkennung

3.1 Hintergrund

Wenn let data = {a:1, b:[11, 22]} , ändern wir sie, nachdem wir sie über Object.defineProperty in einen responsiven Typ konvertiert haben, data.a = 2 , wodurch die Außenwelt benachrichtigt wird. Das ist leicht zu verstehen. Ebenso wird data.b = [11, 22, 33] die Außenwelt benachrichtigen. Wenn wir jedoch data b auf eine andere Weise ändern, etwa data.b.push(33) , wird die Außenwelt nicht benachrichtigt, da der Setter nicht verwendet wird. Siehe das Beispiel:

Funktion defineReactive(Objekt, Schlüssel, Wert) {
    Objekt.defineProperty(Objekt, Schlüssel, {
      aufzählbar: wahr,
      konfigurierbar: true,
      erhalten: Funktion () {
        konsole.log(`get val = ${val}`)
        Rückgabewert
      },
      set: Funktion reactiveSetter (newVal) {
        wenn(Wert === neuerWert){
            zurückkehren
        }
        Konsole.log(`set val = ${newVal}; oldVal = ${val}`)
        val = neuerWert
      }
    });
}

// Das Folgende ist der Testcode {1}
lass Daten = {}
defineReactive(Daten, 'a', [11,22])
data.a.push(33) // get val = 11,22 (Setter nicht ausgelöst) {2}     
data.a // Wert abrufen = 11,22,33 
data.a = 1 // setze Wert = 1; alterWert = 11,22,33 (Setter auslösen)

Das Ändern des Wertes des Arrays durch die push()-Methode löst den Setter (Zeile {2}) nicht aus, so dass die Außenwelt nicht benachrichtigt werden kann. Dies scheint ein Problem zu veranschaulichen: Durch die Methode Object.definePropery() können nur Objekte in Reaktionsfähigkeit umgewandelt werden, Arrays jedoch nicht.

Tatsächlich kann Object.definePropery() Arrays in reaktionsfähige Arrays umwandeln. Siehe das Beispiel:

// Fahren Sie mit dem obigen Beispiel fort und ändern Sie den Testcode (Zeile {1}) wie folgt:
lass Daten = []
defineReactive(Daten, '0', 11)
Daten[0] = 22 // setze Wert = 22; alterWert = 11
data.push(33) // wird nicht ausgelöst {10}

Obwohl Object.definePropery() ein Array reaktionsfähig machen kann, wird die Außenwelt durch eine Modifizierung des Arrays über data.push(33) (Zeile {10}) trotzdem nicht benachrichtigt.

Daher werden in Vue zwei Methodensätze verwendet, um Daten in Reaktionsfähigkeit umzuwandeln: Objekte verwenden Object.defineProperty(); Arrays verwenden einen anderen Satz.

3.2 Umsetzung

In es6 kann Proxy verwendet werden, um Änderungen in Arrays zu erkennen. Siehe das Beispiel:

lass Daten = [11,22]
let p = neuer Proxy(Daten, {
    set: Funktion(Ziel, Eigenschaft, Wert, Empfänger) {
        Ziel[Eigenschaft] = Wert;
        console.log('Eigenschaftssatz: ' + Eigenschaft + ' = ' + Wert);
        gibt true zurück;
    }
    })
konsole.log(p)
p.drücken(33)
/*
Ausgabe:
[ 11 , 22 ]
Eigenschaftssatz: 2 = 33
Eigenschaftssatz: Länge = 3
*/

Vor es6 war es etwas problematischer und Sie konnten Interceptors verwenden. Das Prinzip ist: Wenn wir [].push() ausführen, wird die Methode im Array-Prototyp (Array.prototype) aufgerufen. Wir fügen einen Interceptor zwischen [].push() und Array.prototype Wenn [].push() in Zukunft aufgerufen wird, wird zuerst die push()-Methode im Interceptor ausgeführt, und die push()-Methode im Interceptor ruft die push()-Methode in Array.prototype auf. Siehe das Beispiel:

// Array-Prototyp let arrayPrototype = Array.prototype

// Einen Interceptor erstellen let interceptor = Object.create(arrayPrototype)

// Ordnen Sie den Interceptor den Methoden des ursprünglichen Arrays zu; ('push,pop,unshift,shift,splice,sort,reverse').split(',')
.forEach(Methode => {
    let Herkunft = ArrayPrototyp[Methode];
    Objekt.defineProperty(Interceptor, Methode, {
        Wert: Funktion(...args){
            Konsole.log(`Interceptor: args = ${args}`)
            gib Ursprung zurück.apply(dies, Argumente);
        },
        aufzählbar: falsch,
        beschreibbar: true,
        konfigurierbar: true
    })
});

// Testen Sie let arr1 = ['a']
sei arr2 = [10]
arr1.push('b')
// Änderungen im Array arr2 erkennen Object.setPrototypeOf(arr2, interceptor) // {20}
arr2.push(11) // Abfangjäger: args = 11
arr2.unshift(22) // Abfangjäger: args = 22

Dieses Beispiel fügt dem Interceptor sieben Methoden hinzu, die den Inhalt des Arrays selbst ändern können. Wenn Sie Änderungen an einem Array erkennen müssen, richten Sie den Prototyp des Arrays auf den Interceptor (Zeile {20}). Wenn wir das Array über 7 Methoden wie Push ändern, wird es im Interceptor ausgelöst, sodass die Außenwelt benachrichtigt werden kann.

An diesem Punkt haben wir nur die Aufgabe der Erkennung von Array-Änderungen abgeschlossen.

Wenn sich Daten ändern, benachrichtigen Sie die Außenwelt. Die obige Kodierungsimplementierung gilt nur für Objektdaten, hier müssen wir sie jedoch für Array-Daten implementieren.

Lassen Sie uns über die gleiche Frage nachdenken:

1. Wie erkennt man Änderungen in einem Array?

  • Abfangjäger

2. Wen benachrichtigen wir bei Datenänderungen?

  • Beobachter

3. Auf wen kann man sich verlassen?

  • Beobachter

4. Wann werden Sie benachrichtigt?

  • Beim Ändern von Daten. Benachrichtigung im Abfangjäger.

5. Wann sollen Abhängigkeiten erfasst werden?

  • Denn wir müssen die Stellen informieren, an denen die Daten genutzt werden. Um Daten zu verwenden, müssen Sie Daten lesen. Wird beim Lesen der Daten erhoben. Dies ist dasselbe wie Objektsammlungsabhängigkeiten.
  • {a: [11,22]} Wenn wir beispielsweise Array a verwenden möchten, müssen wir auf das Attribut a des Objekts zugreifen.

6. Wo werden die Daten erhoben?

  • Das Objekt sammelt Abhängigkeiten in jedem Attribut, aber hier müssen wir berücksichtigen, dass das Array Abhängigkeiten im Interceptor auslösen kann und die Position möglicherweise angepasst werden muss

Das ist alles, ich werde hier nicht ins Detail gehen. Im nächsten Artikel werde ich den Quellcode zur Datenerkennung in Vue extrahieren und ihn in Verbindung mit diesem Artikel kurz analysieren.

IV. Fragen zu Array

// Sie müssen vue.js selbst importieren. In Zukunft werden wir versuchen, nur den Kerncode aufzulisten <div id='app'>
        <Abschnitt>
            {{ p1[0] }}
            {{ p1[1] }}
        </Abschnitt>
</div>
<Skript>
const app = new Vue({
    el: '#app',
    Daten: {
        p1: ['ph', '18']
    }
})
</Skript>

Nach dem Ausführen wird auf der Seite ph 18 angezeigt. Die Konsole führt app.p1[0] = 'lj' aus und die Seite reagiert nicht, da das Array die Außenwelt nur über den Interceptor benachrichtigen kann, indem es die angegebenen 7 Methoden aufruft. Wenn Sie app.$set(app.p1, 0, 'pm') wird der Seiteninhalt zu pm 18 .

Das Obige ist eine kurze Analyse der grundlegenden Implementierung von Änderungen der Vue-Erkennungsdaten. Weitere Informationen zu Änderungen der Vue-Erkennungsdaten finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Vue implementiert 3 Möglichkeiten zum Wechseln zwischen Registerkarten und zum Beibehalten des Datenstatus
  • Analyse und Lösung von Datenverlusten während der Wertübertragung von Vue-Komponenten
  • Implementierung einer Großbilddarstellung der Datenvisualisierung basierend auf vue+echarts
  • Implementierung der Drag-Datenvisualisierungsfunktion in Vue basierend auf Echarts
  • Vue ruft die Daten ab, kann sie aber nicht auf der Seite darstellen
  • Die Antd-Vue-Tabellenkomponente fügt ein Klickereignis hinzu, um auf eine Datenzeile zu klicken (Tutorial)
  • vue+echarts+datav Datenanzeige auf großem Bildschirm und Implementierung einer Drilldown-Funktion für Provinzen, Städte und Landkreise auf einer Karte Chinas
  • In Vuex aufgetretene Fallstricke, Vuex-Datenänderungen, Seiten-Rendering-Vorgänge in Komponenten
  • Vue implementiert Datenaustausch- und Änderungsvorgänge zwischen zwei Komponenten

<<:  Installationsprozess von CentOS8 Linux 8.0.1905 (Abbildung)

>>:  Detaillierte Erläuterung der Galera-Cluster-Bereitstellung im Clustermodus von MySQL

Artikel empfehlen

Tools zum Konvertieren statischer Websites in RSS

<br /> Dieser Artikel wurde von Rachel Golds...

Details zum Lazy Loading im Vue-Routing

Inhaltsverzeichnis 1. Was ist Lazy Loading von Ro...

Detailliertes Tutorial zur Installation von Protobuf 3 unter Ubuntu

Wann ist die Installation durchzuführen? Wenn Sie...

Analyse des MySQL-Client-Installationsprozesses auf dem Mac

Versuchen Sie die Installation über Pip in einer ...

Tutorial zur Verwendung des Frameset-Tags in HTML

Frameset-Seiten unterscheiden sich etwas von norm...

Grafisches Tutorial zur MySQL 5.7-Konfiguration ohne Installation

Mysql ist eine beliebte und einfach zu bedienende...

Lösung für die Docker-Befehlsausnahme „Zugriff verweigert“

Installieren Sie Docker im Linux-System neu und g...

Docker startet im Status „Beendet“

Nach dem Docker-Lauf ist der Status immer „Beende...