Schauen Sie sich zunächst das Bild an, um den allgemeinen Vorgang und die Vorgehensweise zu verstehen InitialisierungWenn ein neuer Vue initialisiert wird, werden auch die Eigenschaften und Daten unserer Komponente initialisiert. Da dieser Artikel hauptsächlich die Reaktionsfähigkeit einführt, werde ich die anderen Aspekte nicht im Detail erläutern. Werfen wir einen Blick auf den Quellcode. Quellcodeadresse: src/core/instance/init.js – Zeile 15 Exportfunktion initMixin (Vue: Klasse<Komponente>) { // Füge die Methode _init zum Prototyp hinzu Vue.prototype._init = function (options?: Object) { ... vm._self = vm initLifecycle(vm) // Initialisiere Instanzeigenschaften und -daten: $parent, $children, $refs, $root, _watcher... usw. initEvents(vm) // Initialisiere Ereignisse: $on, $off, $emit, $once initRender(vm) // Rendering initialisieren: render, mixin callHook(vm, 'beforeCreate') // Rufe die Lifecycle-Hook-Funktion auf initInjections(vm) // Initialisiere Injection initState(vm) // Komponentendaten initialisieren: Eigenschaften, Daten, Methoden, Überwachung, berechnet initProvide(vm) // Provide initialisieren callHook(vm, „erstellt“) // Lebenszyklus-Hook-Funktion aufrufen … } } Hier werden zur Initialisierung viele Methoden aufgerufen, die jeweils unterschiedliche Dinge tun, und die Reaktionsfähigkeit bezieht sich hauptsächlich auf die Dateneigenschaften und Daten innerhalb der Komponente. Dieser Teil befindet sich in der Methode initState(). Sehen wir uns also den Quellcode dieser Methode an. initState()Quellcodeadresse: src/core/instance/state.js – Zeile 49 Exportfunktion initState (vm: Komponente) { vm._watchers = [] const opts = vm.$optionen // Requisiten initialisieren wenn (opts.props) initProps(vm, opts.props) // Initialisierungsmethoden wenn (opts.methods) initMethods(vm, opts.methods) //Daten initialisieren wenn (opts.data) { initData(vm) } anders { // Wenn keine Daten vorhanden sind, ist der Standardwert ein leeres Objekt, und beobachten Sie (vm._data = {}, true /* asRootData */). } // Berechnete Werte initialisieren wenn (opts.computed) initComputed(vm, opts.computed) // Uhr initialisieren wenn (opts.watch && opts.watch !== nativeWatch) { initWatch(vm, opts.watch) } } Auch hier werden eine Reihe von Initialisierungsmethoden aufgerufen. Kommen wir gleich zum Punkt und nehmen diejenigen, die sich auf unsere responsiven Daten beziehen, nämlich initProps(), initData() und observe() initProps()Quellcodeadresse: src/core/instance/state.js – Zeile 65 Die wichtigsten Dinge, die hier getan werden, sind:
Funktion initProps (vm: Komponente, propsOptions: Objekt) { // Die übergeordnete Komponente übergibt Eigenschaften an die untergeordnete Komponente const propsData = vm.$options.propsData || {} // Endgültige Eigenschaften nach der Konvertierung const props = vm._props = {} //Speichere den Schlüssel der Props. Auch wenn der Props-Wert leer ist, wird der Schlüssel darin enthalten sein const keys = vm.$options._propKeys = [] const isRoot = !vm.$parent // Props von Nicht-Root-Instanzen konvertieren wenn (!isRoot) { ToggleObserving(false) } für (const key in propsOptions) { Tasten.drücken(Taste) // Überprüfen Sie den Props-Typ, die Standardattribute usw. const value = validateProp(key, propsOptions, propsData, vm) // In einer Nicht-Produktionsumgebung, wenn (process.env.NODE_ENV !== 'production') { const hyphenatedKey = Bindestrich(Schlüssel) wenn (istReserviertesAttribut(Schlüssel mit Bindestrich) || config.isReservedAttr(Schlüssel mit Bindestrich)) { warnen(`hyphenatedKey ist eine reservierte Eigenschaft und kann nicht als Komponenteneigenschaft verwendet werden`) } // Props so einstellen, dass sie reagieren defineReactive(props, key, value, () => { // Warnen, wenn der Benutzer Eigenschaften ändert, if (!isRoot && !isUpdatingChildComponent) { warnen(`Direktes Ändern von Requisiten vermeiden`) } }) } anders { //Requisiten so einstellen, dass sie reagieren. defineReactive(props, key, value) } // Übertrage Eigenschaften, die sich nicht auf der Standard-VM befinden, auf die Instanz //, sodass auf vm._props.xx über vm.xx zugegriffen werden kann, if (!(key in vm)) { Proxy (vm, „_props“, Schlüssel) } } umschaltenBeobachtung(true) } initData()Quellcodeadresse: src/core/instance/state.js – Zeile 113 Die wichtigsten Dinge, die hier getan werden, sind:
Funktion initData (vm: Komponente) { // Daten der aktuellen Instanz abrufen let data = vm.$options.data // Bestimmen Sie den Datentyp data = vm._data = typeof data === 'function' ? getData(Daten, vm) : Daten || {} wenn (!isPlainObject(data)) { Daten = {} process.env.NODE_ENV !== 'Produktion' && warn(`Datenfunktion sollte ein Objekt zurückgeben`) } // Den Datenattributnamensatz der aktuellen Instanz abrufen const keys = Object.keys(data) // Die Props der aktuellen Instanz abrufen const props = vm.$options.props // Holen Sie das Methodenobjekt der aktuellen Instanz const methods = vm.$options.methods sei i = Schlüssel.Länge während (i--) { const Schlüssel = Schlüssel[i] // Bestimmen Sie in einer Nicht-Produktionsumgebung, ob die Methode in Methoden in Eigenschaften vorhanden ist, wenn (process.env.NODE_ENV !== 'production') { if (Methoden && hasOwn(Methoden, Schlüssel)) { warnen(`Methode kann nicht wiederholt deklariert werden`) } } // In einer Nicht-Produktionsumgebung bestimmen, ob das Attribut in den Daten in Props vorhanden ist, wenn (Props && hasOwn(Props, Schlüssel)) { process.env.NODE_ENV !== 'Produktion' && warn(`Eigenschaften können nicht wiederholt deklariert werden`) } sonst wenn (!isReserved(Schlüssel)) { // Wenn die Namen nicht gleich sind, Proxy zu vm // vm._data.xx kann über vm.xx auf Proxy(vm, `_data`, Schlüssel) zugreifen } } // Auf Daten warten beobachte(Daten, wahr /* alsRootData */) } beobachten()Quellcodeadresse: src/core/observer/index.js – Zeile 110 Diese Methode wird hauptsächlich verwendet, um den Daten Listener hinzuzufügen. Die wichtigsten Dinge, die hier getan werden, sind:
Exportfunktion beobachten (Wert: beliebig, asRootData: ?boolean): Beobachter | void { // Wenn es nicht vom Typ „Objekt“ oder VNode ist, direkt zurückgeben, wenn (!isObject(Wert) || Wertinstanz von VNode) { zurückkehren } let ob: Beobachter | void // Zwischengespeichertes Objekt verwenden if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { ob = Wert.__ob__ } sonst wenn ( sollteBeobachten && !isServerRendering() && (Array.isArray(Wert) || isPlainObject(Wert)) && Objekt.isExtensible(Wert) && !Wert._isVue ) { //Erstelle einen Listener ob = neuer Observer(Wert) } if (asRootData && ob) { ob.vmCount++ } return ob } BeobachterQuellcode-Adresse: src/core/observer/index.js – Zeile 37 Dies ist eine Klasse, die normale Daten in beobachtbare Daten umwandelt. Die wichtigsten Dinge, die hier getan werden, sind:
Exportklasse Beobachter { Wert: beliebig; abh.: Abh.; vmCount: Zahl; // Die Anzahl der VMs im Root-Objektkonstruktor (Wert: beliebig) { dieser.Wert = Wert dies.dep = neues Dep() this.vmCount = 0 // Füge dem Wert das Attribut __ob__ hinzu, dessen Wert die Observe-Instanz des Werts ist // Dies zeigt an, dass es reagiert. Der Zweck besteht darin, beim Durchlaufen des Objekts direkt zu überspringen, um wiederholte Vorgänge zu vermeiden def(value, '__ob__', this) //Typbeurteilung if (Array.isArray(value)) { // Bestimmen Sie, ob das Array __proty__ hat wenn (hasProto) { // Wenn ja, schreiben Sie die Array-Methode protoAugment(value, arrayMethods) neu. } anders { // Wenn nicht, definieren Sie den Eigenschaftswert über def, d. h. Object.defineProperty copyAugment (value, arrayMethods, arrayKeys). } this.observeArray(Wert) } anders { this.walk(Wert) } } // Wenn es ein Objekttyp ist, walk (obj: Object) { const keys = Objekt.keys(obj) // Alle Eigenschaften des Objekts durchlaufen und in ein responsives Objekt umwandeln. Getter und Setter dynamisch hinzufügen, um eine bidirektionale Bindung zu erreichen for (let i = 0; i < keys.length; i++) { definiereReaktiv(Objekt, Schlüssel[i]) } } //ObserveArray (Elemente: Array<beliebig>) { // Durchlaufe das Array und überwache jedes Element auf (let i = 0, l = items.length; i < l; i++) { beobachten(Elemente[i]) } } } defineReactive()Quellcodeadresse: src/core/observer/index.js – Zeile 135 Der Zweck dieser Methode besteht darin, ein responsives Objekt zu definieren Die wichtigsten Dinge, die hier getan werden, sind:
Exportfunktion defineReactive ( obj: Objekt, Schlüssel: Zeichenfolge, Wert: beliebig, customSetter?: ?Funktion, flach?: Boolesch ) { //Erstellen einer Dep-Instanz const dep = new Dep() // Den Eigenschaftsdeskriptor des Objekts abrufen const property = Object.getOwnPropertyDescriptor(obj, key) if (Eigenschaft && Eigenschaft.konfigurierbar === false) { zurückkehren } // Benutzerdefinierte Getter und Setter abrufen const getter = Eigenschaft && Eigenschaft.get const setter = Eigenschaft && Eigenschaft.set wenn ((!getter || setter) && arguments.length === 2) { val = obj[Schlüssel] } // Wenn val ein Objekt ist, rekursiv beobachten // Durch rekursives Aufrufen von observe kann sichergestellt werden, dass es sich unabhängig davon, wie tief die Objektstruktur verschachtelt ist, um ein responsives Objekt handeln kann. let childOb = !shallow && observe(val) //Fangen Sie die Getter und Setter der Objekteigenschaften ab Objekt.defineProperty(Objekt, Schlüssel, { aufzählbar: wahr, konfigurierbar: true, // Getter abfangen, und die Funktion wird ausgelöst, wenn der Wert abgerufen wird get: function reactiveGetter () { konstanter Wert = Getter? getter.call(obj) : Wert // Führe eine Abhängigkeitssammlung durch // Greife beim Initialisieren des Rendering-Watchers auf das Objekt zu, das eine bidirektionale Bindung erfordert, und löse dadurch die Get-Funktion aus, if (Dep.target) { dep.abhängig() wenn (KindOb) { childOb.dep.depend() wenn (Array.isArray(Wert)) { abhängigArray(Wert) } } } Rückgabewert }, //Setzer abfangen, wenn sich der Wert ändert, wird die Funktion ausgelöst set: function reactiveSetter (newVal) { konstanter Wert = Getter? getter.call(obj) : Wert // Bestimmen, ob eine Änderung aufgetreten ist, wenn (newVal === value || (newVal !== newVal && value !== value)) { zurückkehren } wenn (Prozess.Umgebung.NODE_ENV !== 'Produktion' und customSetter) { benutzerdefinierteSetter() } // Accessor-Eigenschaft ohne Setter if (Getter && !Setter) return wenn (Setter) { setter.call(Objekt, neuerWert) } anders { val = neuerWert } // Wenn der neue Wert ein Objekt ist, beobachten Sie rekursiv childOb = !shallow && observe(newVal) // Update versenden dep.notify() } }) } Wie oben erwähnt, erfolgt die Abhängigkeitssammlung über dep.depend. Man kann sagen, dass Dep der Kern der gesamten Getter-Abhängigkeitssammlung ist. AbhängigkeitssammlungDer Kern der Abhängigkeitssammlung ist Dep und untrennbar mit Watcher verbunden. Werfen wir einen Blick darauf DepQuellcode-Adresse: src/core/observer/dep.js Dies ist eine Klasse, die tatsächlich Watcher verwaltet Initialisieren Sie zunächst ein Subs-Array zum Speichern von Abhängigkeiten, also Beobachtern. Wer von diesen Daten abhängig ist, befindet sich in diesem Array. Definieren Sie dann mehrere Methoden zum Hinzufügen, Löschen, Melden von Aktualisierungen usw. Darüber hinaus verfügt es über ein statisches Attributziel, nämlich einen globalen Watcher. Dies bedeutet auch, dass gleichzeitig nur ein globaler Watcher existieren kann. sei uid = 0 exportiere Standardklasse Dep { statisches Ziel: ?Watcher; ID: Nummer; subs: Array<Watcher>; Konstruktor () { diese.id = uid++ dies.subs = [] } // Einen Beobachter hinzufügen addSub (sub: Watcher) { dies.subs.push(sub) } // Den Beobachter entfernen removeSub (sub: Watcher) { entfernen(diese.subs, sub) } abhängen() { wenn (Dep.target) { //Rufen Sie die addDep-Funktion von Watcher auf: Dep.target.addDep(this) } } // Updates verteilen (im nächsten Abschnitt beschrieben) benachrichtigen () { ... } } // Es wird immer nur ein Beobachter verwendet. Weisen Sie dem Beobachter Dep.target = null zu. const ZielStack = [] Exportfunktion pushTarget (Ziel: ?Watcher) { ZielStack.push(Ziel) Dep.Ziel = Ziel } Exportfunktion popTarget () { targetStack.pop() Dep.target = ZielStack[ZielStack.Länge - 1] } BeobachterQuellcode-Adresse: src/core/observer/watcher.js Watcher ist auch eine Klasse, auch Beobachter (Abonnent) genannt. Die hier ausgeführte Arbeit ist ziemlich kompliziert und verbindet auch Rendering und Kompilierung. Schauen wir uns zuerst den Quellcode an und gehen wir dann den gesamten Prozess der Abhängigkeitssammlung durch. sei uid = 0 exportiere Standardklasse Watcher { ... Konstruktor ( vm: Komponente, expOrFn: Zeichenfolge | Funktion, cb: Funktion, Optionen?: ?Objekt, istRenderWatcher?: Boolesch ) { dies.vm = vm wenn (istRenderWatcher) { vm._watcher = dies } vm._watchers.push(dies) // Array von Dep-Instanzen, die von der Watcher-Instanz gehalten werden this.deps = [] dies.newDeps = [] this.depIds = neues Set() this.newDepIds = neues Set() dieser.Wert = dies.lazy ? nicht definiert : dies.get() wenn (Typ von expOrFn === 'Funktion') { this.getter = expOrFn } anders { this.getter = parsePath(expOrFn) } } erhalten () // Diese Funktion wird zum Zwischenspeichern von Watcher verwendet // Da die Komponente verschachtelte Komponenten enthält, muss der Watcher der übergeordneten Komponente wiederhergestellt werden drückeZiel(dieses) let-Wert const vm = diese.vm versuchen { // Rufe die Rückruffunktion, also upcateComponent, auf, um das Objekt auszuwerten, das eine bidirektionale Bindung benötigt, und löse dadurch die Abhängigkeitssammlung aus. Wert = this.getter.call(vm, vm) } fangen (e) { ... Endlich // Gründliche Überwachung if (this.deep) { traverse(Wert) } // Watcher wiederherstellen popZiel() // Bereinigen Sie unnötige Abhängigkeiten this.cleanupDeps() } Rückgabewert } // Rufe addDep (dep: Dep) auf, wenn die Abhängigkeitssammlung { const id = dep.id wenn (!this.newDepIds.has(id)) { this.newDepIds.add(ich würde) dies.newDeps.push(dep) wenn (!this.depIds.has(id)) { // Schiebe den aktuellen Watcher in das Array dep.addSub(this) } } } // Unnötige Abhängigkeiten bereinigen (unten) bereinigungDeps() { ... } // Wird aufgerufen, wenn Updates versendet werden (unten) aktualisieren () { ... } // Führe den Watcher-Callback aus run () { ... } abhängen() { sei i = this.deps.length während (i--) { dies.deps[i].depend() } } } Auffüllen: Warum kann die in unserer eigenen Komponente geschriebene Uhr automatisch die beiden Parameter „Neuer Wert“ und „Alter Wert“ erhalten? Das heißt, der Rückruf wird in watcher.run() ausgeführt und der neue und der alte Wert werden übergeben. Warum zwei Dep-Instanz-Arrays initialisieren? Da Vue datengesteuert ist, werden die Daten bei jeder Änderung neu gerendert, d. h. die Methode vm.render() wird erneut ausgeführt und der Getter wird erneut ausgelöst. Daher werden zwei Arrays zur Darstellung verwendet: das neu hinzugefügte Dep-Instanzarray newDeps und das zuletzt hinzugefügte Instanzarray deps Prozess der AbhängigkeitssammlungBeim ersten Rendern und Mounten gibt es eine solche Logik mountComponent Quellcodeadresse: src/core/instance/lifecycle.js – Zeile 141 Exportfunktion mountComponent (...): Komponente { //Rufen Sie die Lebenszyklus-Hook-Funktion callHook(vm, 'beforeMount') auf. let updateComponent updateComponent = () => { // Rufen Sie _update auf, um den von render zurückgegebenen virtuellen DOM in den realen DOM zu patchen (d. h. zu differenzieren). Dies ist das erste Rendering vm._update(vm._render(), hydrating) } // Richten Sie einen Beobachter für die aktuelle Komponenteninstanz ein, um die von der Funktion updateComponent erhaltenen Daten zu überwachen. Im Folgenden finden Sie eine Einführung: new Watcher(vm, updateComponent, noop, { // Wenn ein Update ausgelöst wird, wird before() vor dem Update aufgerufen { // Bestimmen Sie, ob das DOM gemountet ist, d. h., es wird beim ersten Rendern und Unmounten nicht ausgeführt, wenn (vm._isMounted && !vm._isDestroyed) { //Rufen Sie die Lifecycle-Hook-Funktion callHook(vm, 'beforeUpdate') auf. } } }, true /* istRenderWatcher */) // Es gibt keinen alten vnode, was darauf hinweist, dass es sich um das erste Rendering handelt, wenn (vm.$vnode == null) { vm._isMounted = wahr //Rufen Sie die Lebenszyklus-Hook-Funktion callHook(vm, 'mounted') auf. } VM zurückgeben } Sammlung von Abhängigkeiten:
Entfernen eines AbonnementsDas Entfernen eines Abonnements erfolgt durch den Aufruf der Methode cleanupDeps(). Wenn beispielsweise v-if in der Vorlage vorhanden ist, sammeln wir die Abhängigkeiten in Vorlage a, die die Bedingungen erfüllen. Bei einer Änderung der Bedingung wird Vorlage B angezeigt und Vorlage A ausgeblendet. Zu diesem Zeitpunkt müssen Sie die Abhängigkeit von einem Die wichtigsten Dinge, die hier getan werden, sind:
// Unnötige Abhängigkeiten bereinigen cleanupDeps () { sei i = this.deps.length während (i--) { const dep = dies.deps[i] wenn (!this.newDepIds.has(dep.id)) { dep.removeSub(dies) } } lass tmp = this.depIds diese.depIds = diese.newDepIds this.newDepIds = tmp dies.newDepIds.clear() tmp = dies.deps dies.deps = dies.newDeps this.newDeps = tmp this.newDeps.length = 0 } Updates verteilen benachrichtigen()Wenn der Setter ausgelöst wird, wird dep.notify() aufgerufen, um alle Abonnenten zu benachrichtigen und Updates zu verteilen. benachrichtigen () { const subs = this.subs.slice() wenn (Prozess.Umgebung.NODE_ENV !== 'Produktion' && !config.async) { // Wenn nicht asynchron, ist eine Sortierung erforderlich, um eine korrekte Auslösung sicherzustellen. subs.sort((a, b) => a.id - b.id) } // Alle Watcher-Instanz-Arrays durchlaufen for (let i = 0, l = subs.length; i < l; i++) { // Update auslösen subs[i].update() } } aktualisieren()Wird aufgerufen, wenn ein Update ausgelöst wird aktualisieren () { wenn (dies.lazy) { dies.schmutzig = wahr } sonst wenn (diese.sync) { dies.laufen() } anders { //Aktualisierungen der Komponentendaten werden hier angezeigt queueWatcher(this) } } Warteschlangenwächter()Quellcodeadresse: src/core/observer/scheduler.js – Zeile 164 Dies ist eine Warteschlange und auch ein Optimierungspunkt, wenn Vue Updates verteilt. Das heißt, der Watcher-Callback wird nicht bei jeder Datenänderung ausgelöst, sondern alle diese Watcher werden zu einer Warteschlange hinzugefügt und dann nach dem nächsten Tick ausgeführt. Dies überschneidet sich mit der Logik von flushSchedulerQueue() im nächsten Abschnitt, daher müssen wir sie zusammen verstehen. Die Hauptaufgaben sind:
Exportfunktion queueWatcher (Watcher: Watcher) { // Holen Sie sich die Watcher-ID const id = watcher.id // Prüfen, ob der Watcher mit der aktuellen ID gepusht wurde if (has[id] == null) { hat[id] = wahr wenn (!spülen) { //Geben Sie hier zuerst queue.push(watcher) ein } anders { // Wenn beim Ausführen der folgenden FlushSchedulerQueue ein neu verteiltes Update vorliegt, wird es hier eingegeben und ein neuer Watcher eingefügt. Das Folgende ist eine Einführung: let i = queue.length - 1 während (i > Index && Warteschlange[i].id > Watcher.id) { ich-- } Warteschlange.splice(i + 1, 0, Beobachter) } // Wird hier zuerst eingetragen if (!waiting) { warten = wahr wenn (Prozess.Umgebung.NODE_ENV !== 'Produktion' && !config.async) { flushSchedulerQueue() zurückkehren } // Da jedes Versenden von Updates zu Rendering führt, setzen Sie alle Beobachter in nextTick und rufen Sie nextTick(flushSchedulerQueue) auf. } } } flushSchedulerQueue()Quellcodeadresse: src/core/observer/scheduler.js – Zeile 71 Die wichtigsten Dinge, die hier getan werden, sind:
Funktion flushSchedulerQueue () { currentFlushTimestamp = getNow() Spülen = wahr lass Beobachter, id // Nach ID sortieren, dabei gelten folgende Bedingungen // 1. Komponentenaktualisierungen müssen in der Reihenfolge vom übergeordneten zum untergeordneten Element erfolgen, da auch beim Erstellungsprozess zuerst das übergeordnete Element und dann das untergeordnete Element erfolgt // 2. Der Watcher, den wir in die Komponente schreiben, hat Vorrang vor dem Rendering-Watcher // 3. Wenn eine Komponente zerstört wird, während der Watcher der übergeordneten Komponente läuft, überspringen Sie diesen Watcher Warteschlange.sortieren((a, b) => a.id - b.id) // Die Warteschlangenlänge nicht im Cache speichern, da sich die Warteschlangenlänge während der Durchquerung ändern kann for (index = 0; index < queue.length; index++) { Beobachter = Warteschlange[Index] wenn (watcher.before) { //Führen Sie die Lebenszyklus-Hook-Funktion watcher.before() für „beforeUpdate“ aus. } id = Beobachter.id hat[id] = null // Führe die Callback-Funktion der Uhr aus, die wir in die Komponente geschrieben haben, und rendere die Komponente watcher.run() // Überprüfen und stoppen Sie die Schleifenaktualisierung. Wenn beispielsweise das Objekt während des Watcher-Prozesses neu zugewiesen wird, tritt eine Endlosschleife auf, wenn (process.env.NODE_ENV !== 'production' && has[id] != null) { kreisförmig[id] = (kreisförmig[id] || 0) + 1 wenn (rundschreiben[id] > MAX_UPDATE_COUNT) { warnen(`Endlosschleife`) brechen } } } // Vor dem Zurücksetzen des Status eine Kopie der Warteschlange aufbewahren const activatedQueue = activatedChildren.slice() const aktualisierteQueue = queue.slice() resetSchedulerState() // Aufrufkomponenten-Aktivierungs-Hook aktiviert rufActivatedHooks auf(activatedQueue) // Aufruf des Komponenten-Update-Hooks aktualisiert rufUpdatedHooks auf(aktualisierteWarteschlange) } aktualisiert()Schließlich können wir aktualisieren. Jeder kennt updated, die Lebenszyklus-Hook-Funktion. Wenn callUpdatedHooks() oben aufgerufen wird, wird es hier eintreten und aktualisiert ausführen Funktion callUpdatedHooks (Warteschlange) { sei i = Warteschlangenlänge während (i--) { const watcher = Warteschlange[i] const vm = watcher.vm wenn (vm._watcher === watcher && vm._isMounted && !vm._isDestroyed) { callHook(vm, 'aktualisiert') } } } An diesem Punkt wurde der Quellcode des responsiven Prinzipprozesses von Vue2 grundsätzlich analysiert. Als Nächstes werde ich die Mängel des obigen Prozesses vorstellen. definierenEigenschaftsmängel und LösungenEs gibt immer noch einige Probleme bei der Verwendung von Object.defineProperty zur Implementierung responsiver Objekte
Und für diese Probleme gibt es in Vue2 auch entsprechende Lösungen Vue.set()Wenn Sie einem Objekt neue responsive Eigenschaften hinzufügen, können Sie eine globale API verwenden, die Vue.set()-Methode Quellcodeadresse: src/core/observer/index.js – Zeile 201 Die Set-Methode akzeptiert drei Parameter:
Die wichtigsten Dinge, die hier getan werden, sind:
Exportfunktionssatz (Ziel: Array<beliebig> | Objekt, Schlüssel: beliebig, Wert: beliebig): beliebig { wenn (Prozess.env.NODE_ENV !== 'Produktion' && (istUndef(Ziel) || istPrimitive(Ziel)) ) { warnen(`Reaktive Eigenschaft kann nicht auf undefinierten, Null- oder primitiven Wert gesetzt werden: ${(target: any)}`) } // Wenn es ein Array ist und der Index gültig ist, if (Array.isArray(target) && isValidArrayIndex(key)) { Ziellänge = Math.max(Ziellänge, Schlüssel) // Verwenden Sie splice, um direkt zu ersetzen. Beachten Sie, dass splice hier nicht nativ ist und daher erkannt werden kann. Weitere Einzelheiten finden Sie unten unter target.splice(key, 1, val) Rückgabewert } // Das bedeutet, es handelt sich um ein Objekt // Wenn der Schlüssel im Ziel vorhanden ist, wird er direkt zugewiesen und kann auch überwacht werden, wenn (Schlüssel in Ziel && !(Schlüssel in Objekt.Prototyp)) { Ziel[Schlüssel] = Wert Rückgabewert } //Ziel abrufen.__ob__ const ob = (Ziel: beliebig).__ob__ if (target._isVue || (ob && ob.vmCount)) { process.env.NODE_ENV !== 'Produktion' && warn( 'Vermeiden Sie das Hinzufügen reaktiver Eigenschaften zu einer Vue-Instanz oder ihren Stamm-$data' + „Zur Laufzeit – deklarieren Sie es im Voraus in der Datenoption.“ ) Rückgabewert } // Wie in Observer eingeführt, bedeutet das Fehlen dieses Attributs, dass es sich nicht um ein responsives Objekt handelt, if (!ob) { Ziel[Schlüssel] = Wert Rückgabewert } // Dann machen Sie das neu hinzugefügte Attribut responsive defineReactive(ob.value, key, val) // Updates manuell versenden ob.dep.notify() Rückgabewert } Überschreiben von Array-MethodenQuellcodeadresse: src/core/observer/array.js Die wichtigsten Dinge, die hier getan werden, sind:
// Den Prototyp des Arrays abrufen const arrayProto = Array.prototype // Ein Objekt erstellen, das den Array-Prototyp erbt. export const arrayMethods = Object.create(arrayProto) // Ändert die Methodenliste des ursprünglichen Arrays const methodsToPatch = [ 'drücken', 'Pop', 'Schicht', 'aufheben', 'spleißen', 'Sortieren', 'umkehren' ] // Array-Ereignismethoden neu schreibenToPatch.forEach(function (method) { //Das ursprüngliche Ereignis speichern const original = arrayProto[method] // Ein responsives Objekt erstellen def(arrayMethods, method, function mutator (...args) { const Ergebnis = original.anwenden(dies, Argumente) const ob = this.__ob__ eingefügt lassen Schalter (Methode) { Fall 'push': Fall 'Unshift': eingefügt = Argumente brechen Fall 'Spleißen': eingefügt = args.slice(2) brechen } if (eingefügt) ob.observeArray(eingefügt) // Updates verteilen ob.dep.notify() //Nach Abschluss der erforderlichen Verarbeitung das ursprüngliche Ereignis ausführen und das Ergebnis zurückgeben }) }) ZusammenfassenDies ist das Ende dieses Artikels über die Interpretation des Quellcodes nach dem responsiven Prinzip durch Vue. Weitere relevante Inhalte zum Quellcode nach dem responsiven Prinzip von Vue finden Sie in den vorherigen Artikeln von 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:
|
<<: So zeigen Sie MySql-Indizes an und optimieren sie
1. Installieren Sie die vsftpd-Komponente Install...
<br />Vorheriges Webdesign-Tutorial: Webdesi...
In vertikaler Richtung können Sie die Ausrichtung...
Nachdem MySQL installiert wurde, können Sie in ei...
Mysql konvertiert Abfrageergebnissatz in JSON-Dat...
[LeetCode] 184. Abteilung Höchstes Gehalt Die Mit...
Phänomen Es gibt mehrere verschachtelte Flex-Stru...
Inhaltsverzeichnis Hintergrund Funktion Zweck Ide...
Server-Abgleichlogik Wenn Nginx entscheidet, in w...
Die Portzuordnung ist nicht die einzige Möglichke...
Inhaltsverzeichnis Vorwort Text Primitive Typen P...
Anfänger können HTML lernen, indem sie einige HTM...
Herausgeber: In diesem Artikel wird die Rolle erö...
Dank der Entwicklung des Internets können wir die...
Viele Tabellen in MySQL enthalten Spalten, die NU...