Dieses Mal zeige ich Ihnen, wie Sie Vue zum Implementieren von Observer verwenden und welche Vorsichtsmaßnahmen für die Verwendung von Vue zum Implementieren von Observer gelten. Das Folgende ist ein praktischer Fall, schauen wir uns das an.
Einführung:
Dieser Artikel ist eine ausführliche Rezension der offiziellen Dokumentation von Vue zu Responsive-Prinzipien (https://cn.vuejs. org/v2/guide /reactivity.html) und stellen Sie den Implementierungsprozess über den Quellcode wieder her.
Das Reaktionsprinzip kann in zwei Schritte unterteilt werden: den Prozess der Sammlung und den Prozess des Auslösens und erneuten Renderns. Es gibt drei sehr wichtige Klassen im Abhängigkeitserfassungsprozess: Watcher, Dep und Observer. In diesem Artikel wird hauptsächlich Observer erläutert.
Dieser Artikel erklärt den Inhalt von Observer, der im vorherigen Artikel nicht behandelt wurde. Schauen wir uns zuerst dieses Bild von der offiziellen Website an:
Das Wichtigste Funktion des Beobachters Es realisiert den Prozess von touch -Data(getter) - Collect als Abhängigkeit im Bild oben, bei dem es sich um den Prozess der Abhängigkeitssammlung handelt.
Nehmen wir den folgenden Code als Beispiel, um ihn zu sortieren:
(Hinweis: Wischen Sie nach links und rechts, um den vollständigen Code anzuzeigen, dasselbe unten)
varvm = newVue({ el: '#demo', data: { firstName: 'Hello', fullName: '' }, watch: { firstName(val) { this.fullName = val + 'TalkingData'; }, } })
In Quellcode, Vue wiederherstellen Der Prozess der Instanziierung, Schritt für Schritt vom Anfang bis zum Quellcode der Observer-Klasse, ist wie folgt (viel Code, der in diesem Artikel nicht behandelt wird, wird weggelassen):
// src/core/instance/index.js functionVue(options) { if(process.env.NODE_ENV !== 'production'&& !(thisinstanceofVue) ) { warn('Vue is a constructor and should be called with the `new` keyword') } this._init(options) } // src/core/instance/init.js Vue.prototype._init = function(options?: Object) { constvm: Component = this // ... initState(vm) // ... } // src/core/instance/state.js exportfunctioninitState(vm: Component) { // ... constopts = vm.$options if(opts.data) { initData(vm) } // ... } functioninitData(vm: Component) { letdata = vm.$options.data data = vm._data = typeofdata === 'function' ? getData(data, vm) : data || {} // ... // observe data observe(data, true/* asRootData */) }
In der initData-Methode beginnen die Daten im Datenelement. Durch die Ausführung von „Beobachtung“ werden alle Daten beobachtbar. Schauen Sie sich als Nächstes den Code der Beobachtungsmethode an:
// src/core/observer/index.js functionobserve(value: any, asRootData: ?boolean): Observer| void{ // 如果不是对象,直接返回 if(!isObject(value) || value instanceofVNode) { return } letob: Observer | void if(hasOwn(value, 'ob') && value.ob instanceofObserver) { // 如果有实例则返回实例 ob = value.ob } elseif( // 确保value是单纯的对象,而不是函数或者是Regexp等情况 observerState.shouldConvert && !isServerRendering() && (Array.isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue ) { // 实例化一个 Observer ob = newObserver(value) } if(asRootData && ob) { ob.vmCount++ } returnob }
Die Funktion der Beobachtungsmethode besteht darin, eine Observer-Instanz für Daten zu erstellen und diese zurückzugeben. Wenn Daten das ob-Attribut haben, bedeutet dies, dass bereits ein Observer vorhanden ist Instanz, und die vorhandene Instanz wird zurückgegeben. Die Antwortdaten von Vue verfügen über ein ob-Attribut, das die Observer-Instanz dieses Attributs speichert, um eine wiederholte Bindung zu verhindern. Schauen wir uns an, was im Prozess des neuen Observer(Werts) passiert:
exportclassObserver{ value: any; dep: Dep; vmCount: number; // number of vms that has this object as root $data constructor(value: any) { this.value = value this.dep = newDep() this.vmCount = 0 def(value, 'ob', this) if(Array.isArray(value)) { // ... this.observeArray(value) } else{ this.walk(value) } } walk (obj: Object) { constkeys = Object.keys(obj) for(leti = 0; i < keys.length; i++) { defineReactive(obj, keys[i], obj[keys[i]]) } } observeArray (items: Array<any>) { for(leti = 0, l = items.length; i < l; i++) { observe(items[i]) } } }
Wie Sie dem Quellcode entnehmen können, werden im Prozess der Instanziierung des Observer zwei Hauptentscheidungen getroffen. Wenn es sich um ein Array handelt, rufen Sie die oberser-Methode erneut für jedes zu beobachtende Element im Array auf. Wenn es sich um ein Nicht-Array-Objekt handelt, durchläuft jedes Attribut des Objekts und ruft die Methode defineReactive darauf auf. Die Methode defineReactive ist hier der Kern! Die Sammlung von Abhängigkeiten wird vervollständigt, indem die Methode Object.defineProperty verwendet wird, um get/set zu jeder Eigenschaft hinzuzufügen, die beobachtet werden muss. Nachdem die Abhängigkeiten erfasst wurden, verfügt jede Eigenschaft über eine Dep zum Speichern aller Watcher-Objekte. Gemäß dem Beispiel am Anfang des Artikels wird get/set zu firstName bzw. fullName hinzugefügt, und jeder von ihnen verfügt über eine Dep-Instanz, um alle Watcher-Objekte zu speichern, die sie beobachten. Das Folgende ist der Quellcode von defineReactive:
exportfunctiondefineReactive( obj: Object, key: string, val: any, customSetter?: ?Function, shallow?: boolean ) { constdep = newDep() // 获取属性的自身描述符 constproperty = Object.getOwnPropertyDeor(obj, key) if(property && property.configurable === false) { return } // cater for pre-defined getter/setters // 检查属性之前是否设置了 getter/setter // 如果设置了,则在之后的 get/set 方法中执行设置了的 getter/setter constgetter = property && property.get constsetter = property && property.set // 通过对属性再次调用 observe 方法来判断是否有子对象 // 如果有子对象,对子对象也进行依赖搜集 letchildOb = !shallow && observe(val) Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: functionreactiveGetter() { // 如果属性原本拥有getter方法则执行 constvalue = getter ? getter.call(obj) : val if(Dep.target) { // 进行依赖收集 dep.depend() if(childOb) { // 如果有子对象,对子对象也进行依赖搜集 childOb.dep.depend() // 如果属性是数组,则对每一个项都进行依赖收集 // 如果某一项还是数组,则递归 if(Array.isArray(value)) { dependArray(value) } } } returnvalue }, set: functionreactiveSetter(newVal) { // 如果属性原本拥有getter方法则执行 // 通过getter方法获取当前值,与新值进行比较 // 如果新旧值一样则不需要执行下面的操作 constvalue = getter ? getter.call(obj) : val /* eslint-disable no-self-compare */ if(newVal === value || (newVal !== newVal && value !== value)) { return } /* eslint-enable no-self-compare */ if(process.env.NODE_ENV !== 'production'&& customSetter) { customSetter() } if(setter) { // 如果属性原本拥有setter方法则执行 setter.call(obj, newVal) } else{ // 如果原本没有setter则直接赋新值 val = newVal } // 判断新的值是否有子对象,有的话继续观察子对象 childOb = !shallow && observe(newVal) // 通知所有的观察者,更新状态 dep.notify() } }) }
Gemäß den chinesischen Kommentaren im Quellcode sollten Sie verstehen können, welche Arbeit während der Ausführung von defineReactive ausgeführt wird. Tatsächlich ist der gesamte Prozess rekursiv und fügt Getter/Setter für jede Eigenschaft hinzu. Für Getter/Setter ist es außerdem erforderlich, die Rekursion (Beurteilung von Unterobjekten) für jedes Attribut Beobachtermuster durchzuführen. Als Getter wird er zum Vervollständigen der Abhängigkeitssammlung verwendet, d. h. dep.depend() im Quellcode. Sobald ein Datenelement seine Set-Methode auslöst, wird für Setter eine Aktualisierungsnachricht veröffentlicht, die alle Beobachter der Daten darüber informiert, dass sie sich ebenfalls ändern werden. Das ist dep.notify() im Quellcode.
Ich glaube, dass Sie die Methode beherrschen, nachdem Sie den Fall in diesem Artikel gelesen haben. Weitere spannende Informationen finden Sie in anderen verwandten Artikeln auf der chinesischen PHP-Website!
Empfohlene Lektüre:
So verwenden Sie die Vue-Dateibaumkomponente
Analyse der zugrunde liegenden Logik von JavaScript EventEmitter
Das obige ist der detaillierte Inhalt vonSo implementieren Sie Observer mit Vue. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!