<am Leben erhalten> <Router-Ansicht /> </am Leben erhalten> Die in Vue integrierte Komponente <keep-alive> kann uns dabei helfen, die Geschwindigkeit des sekundären Seitenzugriffs bei der Entwicklung von SPA-Anwendungen deutlich zu verbessern, indem alle Routenseiten zwischengespeichert werden (natürlich können wir auch gezielt einige Seiten zwischenspeichern). In einigen Szenarien bringt sie jedoch auch Probleme mit sich, darunter zwei Hauptwidersprüche:
In diesem Artikel werden hauptsächlich diese beiden Probleme behandelt, die im folgenden Text als Frage 1 und Frage 2 bezeichnet werden.
Problem 1: ZerstörungWenn die Geschäftslogik komplexer wird, wächst der Routing-Stack allmählich. Theoretisch können Benutzer unendlich routen. Wir müssen zwangsläufig die im Speicher zwischengespeicherten Seitendaten verwalten. Die Seitendaten bestehen aus zwei Teilen, der Vue-Instanz und dem entsprechenden Vnode. Siehe die Definition des Cache in src/core/components/keep-alive.js im Vue-Quellcode this.cache = Object.create(null) //Wird zum Zwischenspeichern von vnode cache[key] => Vnode verwendet this.keys = [] //Wird verwendet, um den Schlüssel des zwischengespeicherten Vnode aufzuzeichnen Nach dem Zwischenspeichern wird der Vnode nicht wiederverwendet, sondern nur die darauf gemountete Vue-Instanz wird verwendet. if (cache[Schlüssel]) { vnode.componentInstance = cache[key].componentInstance //Holen Sie sich die Vue-Instanz nur vom zwischengespeicherten Vnode und hängen Sie sie an den neuen Vnode // machen Sie den aktuellen Schlüssel zum aktuellsten entfernen(Schlüssel, Schlüssel) Tasten.drücken(Taste) } Warum nicht? Weil es einen Fehler gibt. Die früheste Version der Implementierung verwendet den zwischengespeicherten Vnode direkt. Von src/core/components/keep-alive.js Init-Version Standard exportieren { erstellt () { this.cache = Objekt.erstellen(null) }, rendern () { const childNode = this.$slots.default[0] const cid = childNode.componentOptions.Ctor.cid wenn (dieser.cache[cid]) { const child = childNode.child = this.cache[cid].child //Den zwischengespeicherten Vnode direkt abrufen childNode.elm = dies.$el = child.$el } anders { this.cache[cid] = untergeordneter Knoten } childNode.data.keepAlive = true untergeordneten Knoten zurückgeben }, vorZerstören () { für (const key in this.cache) { dies.cache[Schlüssel].child.$destroy() } } } Was wir verwalten müssen, sind eigentlich Cache und Schlüssel. Keep-Alive bietet drei Parameter zur dynamischen Verwaltung des Cache: include – Nur Komponenten mit übereinstimmenden Namen werden zwischengespeichert. Ausschließen: Alle Komponenten, die dem Namen entsprechen, werden nicht zwischengespeichert. max – Die maximale Anzahl von Komponenteninstanzen, die zwischengespeichert werden können. Ihre Funktionen sind sehr einfach und auch der Quellcode ist einfach und leicht zu lesen: Wenn wir also diese Caches verwalten möchten, besteht die einfache Lösung darin, diese drei Parameter zu bedienen, „include“ und „exclude“ zu ändern, um bestimmte Caches zwischenzuspeichern oder zu löschen. Dabei ist jedoch zu beachten, dass sie mit dem Namen der Komponente übereinstimmen: Von src/core/components/keep-alive.js Konstantname: ?string = getComponentName(Komponentenoptionen) Daher werden durch das Leeren des Caches alle Instanzen einer Komponente wahllos gelöscht, was offensichtlich nicht unseren Anforderungen entspricht. Die Logik von max besteht darin, den Cache am unteren Ende des Stapels zu leeren, wenn der Maximalwert überschritten wird. Aus src/core/components/keep-alive.js: wenn (diese.max && Schlüssel.Länge > parseInt(diese.max)) { pruneCacheEntry(Cache, Schlüssel[0], Schlüssel, this._vnode) } Wir müssen Problem eins lösen. Die offizielle API funktioniert nicht, also müssen wir es selbst machen. Wir müssen zwei Teilprobleme lösen:
1. Wie man zerstörtSehen wir uns zunächst an, wie man es zerstört. Wenn Sie eine Instanz zerstören möchten, ist das ganz einfach. Sie können this.$destroy() direkt verwenden. Ist das in Ordnung? Nein, der ursprüngliche Vnode und der Schlüssel bleiben weiterhin im Cache und in den Schlüsseln erhalten. Beim erneuten Besuch treten Probleme auf. Der Vnode bleibt immer erhalten, aber die Instanz darauf wurde zerstört. Zu diesem Zeitpunkt wird während des Aktualisierungsprozesses von Vue erneut eine Vue-Instanz erstellt. Das heißt, solange eine Keep-Alive-Seite this.$destroy() einmal aufruft, das Cache-Array jedoch nicht gelöscht wird, wird diese Seite beim erneuten Rendern definitiv neu erstellt und natürlich wird der gesamte Lebenszyklus neu gestartet. Das letzte Phänomen besteht darin, dass die Seite scheinbar nicht zwischengespeichert ist. this.$destroy(); //Nicht geeignet für Keep-Alive-Komponenten Daher müssen zum Löschen sowohl der Cache als auch die Schlüssel gelöscht werden. Im Folgenden wird eine $keepAliveDestroy-Methode definiert, die gleichzeitig den Cache löscht: const dtmp = Vue.prototype.$destroy; const f = Funktion() { wenn (dies.$vnode und dieses.$vnode.data.keepAlive) { wenn (diese.$vnode.parent && dies.$vnode.parent.componentInstance && dies.$vnode.parent.componentInstance.cache) { wenn (this.$vnode.componentOptions) { var Schlüssel = !isDef(this.$vnode.key) ? dies.$vnode.componentOptions.Ctor.cid + (dies.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '') : dies.$vnode.key; var cache = this.$vnode.parent.componentInstance.cache; var Schlüssel = this.$vnode.parent.componentInstance.keys; if (cache[Schlüssel]) { if (Schlüssel.Länge) { var index = keys.indexOf(Schlüssel); wenn (Index > -1) { Schlüssel.splice(Index, 1); } } Cache[Schlüssel] löschen; } } } } dtmp.apply(diese, Argumente); } Vue.prototype.$keepAliveDestroy = f; 2. Wann vernichtenWann wird es also zerstört? Es gibt zwei Auslösezeitpunkte:
Ersetzen ist relativ einfach. Wir können die Ersetzungsmethode des Routers direkt abfangen und in dieser Methode die aktuelle Seite löschen. (Hier gibt es Ausnahmen, z. B. beim Wechseln zwischen Tabs, die zuletzt erwähnt werden) Schauen wir uns die Situation mit der Zurück-Route genauer an. Wenn es auf unserer Seite eine Zurück-Schaltfläche gibt, ist es an der Zeit, den Cache zu leeren. Allerdings können wir die integrierte Zurück-Schaltfläche des Browsers und die physische Zurück-Schaltfläche auf Android-Telefonen nicht ignorieren. Wenn man dies berücksichtigt, ist die Lösung, nur die Zurück-Schaltfläche zu verwenden, nicht ausreichend. 2.1 Lösung 1: Verwenden Sie route.query, um die aktuelle Seitenstapeltiefe aufzuzeichnenJedes Push oder Replace fügt der Abfrage einen Parameter hinzu, um die aktuelle Tiefe aufzuzeichnen. dies.$router.push({ Pfad:"/Ziel", Abfrage:{ stackLevel: Zahl(this.$route.query.stackLevel) + 1 } }) Diese Lösung hat offensichtliche Nachteile. Es ist sehr hässlich und gefährlich, einen Parameter extern verfügbar zu machen. Benutzer können ihn nach Belieben ändern. Beim Bewerben einer Website kann der vom Unternehmen in die Produktionsumgebung kopierte Werbelink auch das seltsame Suffix https://xxx.com/foo?bar=123&stackLevel=13 haben. Missbilligung 2.2 Lösung 2 verwendet die Vue-Instanz selbst, um die aktuelle Stapeltiefe aufzuzeichnenNachdem die Push- und Replace-Methoden des Routers gehackt wurden, kann bei jedem Seitensprung ein _stackLevel auf der VM der Zielseite gemountet werden. Dies löst das Problem der ersten Lösung. Es wird den Benutzern nicht angezeigt, ist in der URL nicht sichtbar und kann nicht geändert werden. Wir können jedoch einen anderen Dämon im Browser nicht ignorieren – die Schaltfläche „Aktualisieren“. Beim Aktualisieren ändert sich die URL nicht, aber die VM-Instanz muss neu erstellt werden, sodass unsere Stapeltiefenmarkierung verloren geht. Missbilligung 2.3 Lösung 3: Verwenden Sie history.state, um die Stapeltiefe aufzuzeichnenDas Endergebnis ist dann für den Benutzer unsichtbar und kann beim Aktualisieren gespeichert werden. Das ist history.state. Wir müssen also die Stapeltiefe in history.state speichern, wodurch die gesamte Routing-Kette vollständig gespeichert werden kann. Wenn wir feststellen, dass die Stapeltiefe der Zielseite geringer ist als die der aktuellen Seite, können wir die aktuelle Seite zerstören. wenn (Zielstapel < aktueller Stapel) { aktuell.$keepAliveDestroy(); } Problem 2: Mehrere Instanzen derselben Seite mit unterschiedlichen Parametern zwischenspeichernSie können src/core/components/keep-alive.js im Quellcode sehen const-Schlüssel: ?string = vnode.key == null // derselbe Konstruktor kann als unterschiedliche lokale Komponenten registriert werden // daher reicht cid allein nicht aus (#3269) ? KomponenteOptions.Ctor.cid + (KomponenteOptions.tag ? `::${KomponenteOptions.tag}` : '') : vnode.schlüssel if (cache[Schlüssel]) { vnode.componentInstance = cache[Schlüssel].componentInstance // aktuellen Schlüssel auf den neuesten Stand bringen entfernen(Schlüssel, Schlüssel) Tasten.drücken(Taste) } anders { Cache[Schlüssel] = vnode Tasten.drücken(Taste) // ältesten Eintrag löschen wenn (diese.max && Schlüssel.Länge > parseInt(diese.max)) { pruneCacheEntry(Cache, Schlüssel[0], Schlüssel, this._vnode) } } Wenn ein vnode keinen Schlüssel hat, wird der Komponentenname verwendet. Daher ist der Schlüssel im Standardcache der Komponentenname. Wenn die Komponenten gleich sind, können wir dieses Problem lösen, indem wir jeder Seite einen eigenen Schlüssel geben. Wie können wir erreichen, dass jede Seite einen eigenen Schlüssel hat? Es gibt zwei Unterfragen:
1. So werden Sie einzigartig1.1 Zeitstempel, große ZufallszahlSchlüssel = Datum.jetzt() 1.2 Routing-Stackhöhe + Pfadnamekey = vm._stack + router.currentRoute.path Diese Lösung verwendet die aktuelle Stackhöhe + Pfadnamen. Wozu wird der Pfadname benötigt? Weil beim Ersetzen die Stackhöhe unverändert bleibt, ändert sich nur der Pfadname. 2. So weisen Sie dem Vnode einer Seite einen Schlüssel zuDerzeit gibt es zwei Lösungen, um dem Schlüssel des aktuellen Vnode des Vue-Routers einen Wert zuzuweisen: 2.1 Schlüssel dynamisch über route.query bindenDiese Lösung ist relativ einfach zu implementieren // Taste binden ... <router-view :key='$route.query.routerKey' /> ... //Beim Pushen von this.$router.push({ Pfad: „/foo“, Abfrage:{ routerKey: Date.now() //Zufälliger Schlüssel } }) Diese Methode ist sehr einfach und effektiv, hat aber den Nachteil, dass sie auch einen seltsamen Parameter in der URL offenlegt 2.2 Direkte Wertezuweisung durch Abrufen von VnodeIn welcher Phase wird der Schlüssel von Vnode zugewiesen? Die Antwort ist offensichtlich. Bevor die Keep-Alive-Komponenten-Renderfunktion eintritt, src/core/components/keep-alive.js ... rendern () { const slot = this.$slots.default const vnode: VNode = getFirstComponentChild(Steckplatz) ... Wir können die Keep-Alive-Renderfunktion hacken, dann den ersten untergeordneten Knoten im Slot abrufen, seinem Schlüssel einen Wert zuweisen und dann das Keep-Alive-Rendern aufrufen: const tmp = vm.$options.render //vm ist eine Keep-Alive-Komponenteninstanz vm.$options.render = Funktion() { const slot = this.$slots.default; const vnode = getFirstComponentChild(slot) // vnode ist ein Keep-Alive-Komponenten-vnode if (VerlaufSollteÄndern) { wenn (!isDef(vnode.key)) { if (istErsetzen) { vnode.key = genKey(router._stack) } sonst wenn (isPush()) { vnode.key = genKey(Zahl(router._stack) + 1) } anders { vnode.key = genKey(Zahl(router._stack) - 1) } } } anders { // wenn historyShouldChange false ist, sollte nur erneut gerendert werden, es sollte keine neue VM erstellt werden, verwenden Sie den gleichen vnode.key, Problem Nr. 7 vnode.key = genKey(router._stack) } returniere tmp.apply(diese, Argumente) } ZusammenfassenDurch die obige Problemanalyse haben wir das Kernproblem der automatischen Cache-Verwaltung gelöst. Dieser Artikel ist eine Zusammenfassung der Open-Source-Bibliothek vue-router-keep-alive-helper. Diese Bibliothek ist ein einfaches und benutzerfreundliches Tool zur automatischen Verwaltung des Keep-Alive-Cache, das das Problem der Vue-Cache-Verwaltung löst. Wenn es für Sie nützlich ist, danke für Ihren großzügigen Stern. Demo-Beispielcode Danke für das Bilibili-Demovideo. Oben finden Sie Einzelheiten zum Verwalten zwischengespeicherter Seiten in Vue. Weitere Informationen zu zwischengespeicherten Seiten in Vue finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM! Das könnte Sie auch interessieren:
|
<<: Tutorial zum Konfigurieren und Verwenden des i3-Fenstermanagers unter Linux
Verwenden Sie zum Crawlen von Daten die browserba...
Die Entsprechung zwischen der Tensorflow-Version ...
Das Definieren des Datenfeldtyps in MySQL ist für...
Mit dem Wissen über CSS-Variablen werde ich den C...
1. Hintergrund Im Kontext schneller Updates und I...
Im vorherigen Artikel wurde vorgestellt, wie Vue ...
1. golang:neuestes Basis-Image mkdir gotest Berüh...
Lassen Sie mich Ihnen zunächst vorstellen, dass d...
Das Tbody-Element sollte in Verbindung mit den Ele...
Tutorial zur Installation und Kennworteinstellung...
Sie erinnern sich vielleicht, dass wir in den ver...
Detailliertes Beispiel für die Datenmigration bei...
CSS-Importmethode - Inline Durch das Style-Tag-At...
Fehlermeldung: FEHLER 2002: Verbindung zum lokale...
In diesem Artikel erfahren Sie, wie Sie die Boots...