Vorwort: Kürzlich musste das Team etwas teilen, aber ich wusste nicht, wie ich es teilen sollte. Schließlich dachte ich, dass ich schon immer den Vue-Quellcode studieren wollte, und habe heute einfach „diese Gelegenheit genutzt“, um ihn zu studieren.
Es gibt bereits viele Artikel zum Thema Vue-Datenbindung im Internet, aber es selbst zu schreiben, eine Demo zu tippen und die Artikel anderer Leute zu lesen, ist völlig anders, also ... Die Träger kommen
Derzeit gibt es drei Hauptmethoden zur Implementierung der Datenbindung:
1. Dirty Value Check (angular.js) Polling zur Erkennung von Datenänderungen
DOM-Ereignisse, wie z. B. die Eingabe von Text durch Benutzer, Klicken auf Schaltflächen usw. . (ng-click)
XHR-Antwortereignis ($http)
Browser-Standortänderungsereignis ($location)
Timer-Ereignis ($timeout, $interval)
Führen Sie $digest() oder $apply() aus
2. Object.defineProperty entführt das Get und Set des Objekts, um die Daten zu überwachen. (vue)
3. Der Publisher/Subscriber-Modus realisiert die automatische Synchronisierung von Daten und Ansichten
Vorteile von Object.defineProperty
„Dirty Value Detection“ – Datenänderungen Abschließend a Es wird ein Test der Bindungsbeziehung zwischen allen Daten und Ansichten durchgeführt, um festzustellen, ob sich Daten geändert haben. Die Verarbeitung von Änderungen kann weitere Änderungen in anderen Daten zur Folge haben, sodass dieser Prozess mehrere Male durchlaufen kann, bis er nicht mehr vorhanden ist Daten werden an die Ansicht gesendet und die Seite wird aktualisiert, um
Object.defineProperty() anzuzeigen. Überwachen Sie die Vorgänge für die Daten und lösen Sie automatisch die Datensynchronisierung aus. Da die Synchronisierung außerdem für verschiedene Daten ausgelöst wird, können Änderungen genau an die gebundene Ansicht gesendet werden, anstatt einen Test für alle Daten durchzuführen.
Verwendung von Object.defineProperty
var a = {}; Object.defineProperty(a, "b", { set: function (newValue) { console.log("我被赋值了!" + newValue); }, get: function () { console.log("我被取值了!"); return 2 } }) a.b = 3; //我被赋值了! console.log(a.b); //我被取值了! //打印 2
Wie aus dem obigen Beispiel ersichtlich ist, übergibt Object.defineProperty 3 Parameter
Der erste : ein Objekt
zweitens: b-Attribut in einem Objekt
drittens: weitere Attribute, Auflistung nützlicher Werte, Festlegen, Abrufen, konfigurierbar
Datenbindung Festgelegtes Prinzip:
1. Implementieren Sie einen Daten-Listener-Beobachter, um alle Attribute des Datenobjekts zu überwachen, rufen Sie den neuesten Wert ab und benachrichtigen Sie das Dep-Array.
2. Implementieren Sie eine Anweisung. Der Parser scannt und analysiert die Anweisungen jedes Elementknotens und ersetzt die Daten gemäß der Anweisungsvorlage
3. Implementieren Sie ein dep-Array, das jede Attributänderung abonnieren und Benachrichtigungen über diese empfangen und die Anweisungsbindung ausführen kann. Die entsprechende Rückruffunktion aktualisiert die Ansicht
1. Beobachter implementieren
var data = {name: 'beidan'}; observe(data); data.name = 'test'; // 监听到值变化了 beidan 变成 test function observe(data) { if (!data || typeof data !== 'object') { return; } // 取出所有属性遍历 Object.keys(data).forEach(function(key) { defineReactive(data, key, data[key]); }); }
function defineReactive(data, key, val) { Object.defineProperty(data, key, { enumerable: true, // 可枚举 configurable: false, // 不能再define get: function() { return val; }, set: function(newVal) { console.log('监听到值变化了 ', val, ' 变成 ', newVal); val = newVal; } }); }
function Dep() { this.subs = []; } Dep.prototype = { addSub: function (sub) { this.subs.push(sub); }, notify: function (val) { this.subs.forEach(function (sub) { sub.update(val) }); } }; function defineReactive(data, key, val) { Object.defineProperty(data, key, { …… set: function(newVal) { if (val === newVal) return; console.log('监听到值变化了 ', val, ' 变成 ', newVal); val = newVal; dep.notify(val); // 通知所有订阅者 } }); }
bindText: function () { var textDOMs = this.el.querySelectorAll('[v-text]'), bindText,_context = this; for (var i = 0; i < textDOMs.length; i++) { bindText = textDOMs[i].getAttribute('v-text'); textDOMs[i].innerHTML = this.data[bindText]; var val = textDOMs[i] var up = function (text) { val.innerText = text } _context.dep.addSub({ value: textDOMs[i], update: up }); } },