Heim  >  Artikel  >  Web-Frontend  >  Vue-Quellcode-Analyse des Observer-Implementierungsprozesses

Vue-Quellcode-Analyse des Observer-Implementierungsprozesses

亚连
亚连Original
2018-05-28 13:55:291386Durchsuche

In diesem Artikel wird hauptsächlich der Observer-Implementierungsprozess der Vue-Quellcode-Analyse vorgestellt. Die Hauptfunktion von Observer besteht darin, den Prozess der Erfassung von Berührungsdaten (Getter) als Abhängigkeit zu implementieren sind interessiert Lasst uns gemeinsam lernen

Einführung:

Dieser Artikel ist ein ausführliches reaktives Prinzip der offiziellen Vue-Dokumentation (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 zum Sortieren den folgenden Code als Beispiel:

(Hinweis: Wischen Sie nach links oder rechts, um den vollständigen Code anzuzeigen, dasselbe unten)

varvm = newVue({
el: '#demo',
data: {
firstName: 'Hello',
fullName: ''
},
watch: {
firstName(val) {
this.fullName = val + 'TalkingData';
},
}
})

Im Quellcode ist der Prozess der Instanziierung durch Wiederherstellung von Vue Schritt für Schritt vom Anfang bis zum Quellcode der Observer-Klasse wie folgt (viel Code, der nicht besprochen wird). in diesem Artikel 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 wir, die Daten im Datenelement zu „beobachten“, wodurch alle Daten in „beobachtet“ werden 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 die Daten zu erstellen und diese zurückzugeben Die Daten haben das Attribut ob, was bedeutet, dass sie vorhanden sind. Wenn eine Observer-Instanz vorhanden ist, geben Sie die vorhandene Instanz zurück. 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 neuen Observer(value)-Prozess 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 von Observer. Wenn es sich um ein Array handelt, rufen Sie die oberser-Methode für jedes zu beobachtende Element im Array erneut auf. Wenn es sich um ein Nicht-Array-Objekt handelt, durchlaufen Sie jedes Attribut des Objekts und rufen Sie 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 !== &#39;production&#39;&& customSetter) {
customSetter()
}
if(setter) {
// 如果属性原本拥有setter方法则执行
setter.call(obj, newVal)
} else{
// 如果原本没有setter则直接赋新值
val = newVal
}
// 判断新的值是否有子对象,有的话继续观察子对象
childOb = !shallow && observe(newVal)
// 通知所有的观察者,更新状态
dep.notify()
}
})
}

Laut den chinesischen Kommentaren im Quellcode sollten Sie in der Lage sein, zu verstehen, welche Arbeit während des ausgeführt wird Ausführung von defineReactive. 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, für jede Eigenschaft eine Rekursion durchzuführen (Unterobjekte zu beurteilen), um das Beobachtermuster zu vervollständigen. 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 habe das Obige für Sie zusammengestellt und hoffe, dass es Ihnen in Zukunft hilfreich sein wird.

Verwandte Artikel:

Detaillierte Erläuterung des Unterschieds zwischen vue2.0-Ressourcendatei-Assets und statischen Dateien

Angular 5. x Studiennotizen Router (Routing)-Anwendung

React Router v4 Pit Guide

Das obige ist der detaillierte Inhalt vonVue-Quellcode-Analyse des Observer-Implementierungsprozesses. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn