Zwei Implementierungen des Front-End-Routings von Vue-Router

Zwei Implementierungen des Front-End-Routings von Vue-Router

Da die Geschäftsfunktionen von Front-End-Anwendungen immer komplexer werden und die Anforderungen der Benutzer an das Benutzererlebnis immer höher werden, haben sich Single-Page-Anwendungen (SPA) zur Mainstream-Form von Front-End-Anwendungen entwickelt. Eines der bemerkenswertesten Merkmale großer Single-Page-Anwendungen ist die Verwendung eines Front-End-Routingsystems, das Seitenaufrufe durch Ändern der URL aktualisiert, ohne die Seite erneut anzufordern.

„Aktualisieren der Ansicht ohne erneute Seitenanforderung“ ist eines der Kernprinzipien des Front-End-Routings. Derzeit gibt es zwei Hauptmethoden, um diese Funktion in der Browserumgebung zu implementieren:

  • Ausnutzen des Hashes („#“) in der URL
  • Neue Methoden in HTML5 unter Verwendung der History-Schnittstelle

vue-router ist ein Routing-Plugin für das Vue.js-Framework. Beginnen wir mit dem Quellcode, lesen den Code und die Prinzipien und lernen von oberflächlich nach tiefer, wie vue-router Front-End-Routing mithilfe dieser beiden Methoden implementiert.

Modusparameter

Im Vue-Router wird der Modusparameter verwendet, um den Routing-Implementierungsmodus zu steuern:

const router = neuer VueRouter({
  Modus: "Verlauf",
  Routen: [...]
})

Beim Erstellen eines Instanzobjekts von VueRouter wird der Modus als Konstruktorparameter übergeben. Wenn wir den Quellcode mit Fragen im Hinterkopf lesen, können wir mit der Definition der VueRouter-Klasse beginnen. Im Allgemeinen werden die vom Plug-In bereitgestellten Klassen in der Datei index.js im Stammverzeichnis des Quellcodes src definiert. Öffnen Sie die Datei und Sie können die Definition der VueRouter-Klasse sehen. Die Auszüge zum Modusparameter lauten wie folgt:

exportiere Standardklasse VueRouter {
  
  mode: string; // Der übergebene String-Parameter gibt die Verlaufskategorie anhistory: HashHistory | HTML5History | AbstractHistory; // Die Objekteigenschaft, die tatsächlich funktioniert, muss eine Aufzählung der drei oben genannten Klassen seinfallback: boolean; // Wenn der Browser dies nicht unterstützt, muss der Modus „history“ auf den Modus „hash“ zurückgesetzt werdenconstructor (options: RouterOptions = {}) {
    
    let mode = options.mode || 'hash' // Standardmäßig ist der Modus 'hash' this.fallback = mode === 'history' && !supportsPushState // Verwenden Sie supportsPushState, um zu ermitteln, ob der Browser den Modus 'history' unterstützt if (this.fallback) {
      Modus = "Hash"
    }
    wenn (!imBrowser) {
      mode = 'abstract' // Wenn es nicht in einer Browserumgebung ausgeführt wird, erzwingen Sie den Modus 'abstract'}
    this.mode = Modus

    // Bestimmen Sie die tatsächliche Klasse der Historie basierend auf dem Modus und instanziieren Sie den Schalter (Modus) {
      Anamnese':
        diese.History = neue HTML5History(diese, Optionen.Basis)
        brechen
      Fall 'Hash':
        diese.History = neue HashHistory(diese, Optionen.Basis, diese.Fallback)
        brechen
      Fall 'abstrakt':
        diese.History = neue AbstractHistory(diese, options.base)
        brechen
      Standard:
        wenn (Prozess.Umgebung.NODE_ENV !== 'Produktion') {
          assert(false, `ungültiger Modus: ${mode}`)
        }
    }
  }

  init (app: any /* Vue-Komponenteninstanz */) {
    
    const history = diese.geschichte

    // Führen Sie die entsprechenden Initialisierungsvorgänge und die Überwachung entsprechend der Verlaufskategorie durch, wenn (Verlaufsinstanz von HTML5History) {
      Verlauf.Übergang zu(Verlauf.getCurrentLocation())
    } sonst wenn (History-Instanz von HashHistory) {
      const setupHashListener = () => {
        Verlauf.setupListeners()
      }
      Verlauf.ÜbergangZu(
        Verlauf.getCurrentLocation(),
        setupHashListener,
        HashListener einrichten
      )
    }

    Verlauf.listen(route => {
      diese.apps.forEach((app) => {
        app._route = Route
      })
    })
  }

  // Die folgende von der VueRouter-Klasse bereitgestellte Methode ruft tatsächlich die Methode des spezifischen Verlaufsobjekts push (location: RawLocation, onComplete?: Function, onAbort?: Function) { auf.
    this.history.push(Standort, bei Abschluss, bei Abbruch)
  }

  ersetzen (Standort: Rohstandort, bei Abschluss?: Funktion, bei Abbruch?: Funktion) {
    this.history.replace(Standort, bei Abschluss, bei Abbruch)
  }
}

Man kann Folgendes erkennen:

Der als Parameter übergebene String-Attributmodus ist lediglich ein Marker, der die Implementierungsklasse des Objektattributverlaufs angibt, die tatsächlich funktioniert. Die entsprechende Beziehung zwischen den beiden ist wie folgt:

Modus Geschichte Hash Abstrakt
Geschichte HTML5Geschichte HashHistorie ZusammenfassungGeschichte

Vor dem Initialisieren des entsprechenden Verlaufs werden einige Prüfungen des Modus durchgeführt: Wenn der Browser die Methode HTML5History nicht unterstützt (beurteilt durch die Variable „supportsPushState“), wird der Modus zwangsweise auf „Hash“ gesetzt; wenn er nicht in einer Browserumgebung ausgeführt wird, wird der Modus zwangsweise auf „Abstrakt“ gesetzt.

Die Methoden onReady(), push() und andere in der VueRouter-Klasse sind nur Proxys. Sie rufen tatsächlich die entsprechenden Methoden des spezifischen Verlaufsobjekts auf. Bei der Initialisierung in der Methode init() werden je nach spezifischer Kategorie des Verlaufsobjekts unterschiedliche Vorgänge ausgeführt.

Die beiden Methoden in der Browserumgebung werden in den Klassen HTML5History bzw. HashHistory implementiert. Sie sind alle im Ordner „src/history“ definiert und erben von der History-Klasse, die in der Datei „base.js“ im selben Verzeichnis definiert ist. History definiert allgemeine und grundlegende Methoden, deren direktes Lesen verwirrend sein kann. Beginnen wir mit den bekannten Methoden push() und replace() in den Klassen HTML5History und HashHistory.

HashHistorie

Lassen Sie uns zunächst das Prinzip wiederholen, bevor wir uns den Quellcode ansehen:

Das Rautezeichen („#“) wird ursprünglich zur URL hinzugefügt, um den Speicherort der Webseite anzugeben:

www.example.com/index.html#…

Das #-Symbol selbst und die ihm folgenden Zeichen werden als Hash bezeichnet und können über die Eigenschaft window.location.hash gelesen werden. Es verfügt über die folgenden Funktionen:

  • Obwohl der Hash in der URL erscheint, ist er nicht in der HTTP-Anfrage enthalten. Es wird verwendet, um Browseraktionen zu steuern und ist für den Server völlig nutzlos. Daher wird die Seite beim Ändern des Hashs nicht neu geladen.
  • Sie können Listener-Ereignisse für Hash-Änderungen hinzufügen:
window.addEventListener("hashchange", funcRef, false)

Jedes Mal, wenn der Hash (window.location.hash) geändert wird, wird dem Zugriffsverlauf des Browsers ein Datensatz hinzugefügt.

Durch die Verwendung der oben genannten Hash-Eigenschaften können Sie im Front-End-Routing die Funktion „Ansicht aktualisieren, aber Seite nicht erneut anfordern“ implementieren.

HashHistory.push()

Schauen wir uns die push()-Methode in HashHistory an:

push (Standort: Rohstandort, bei Abschluss?: Funktion, bei Abbruch?: Funktion) {
  dies.transitionTo(Standort, Route => {
    pushHash(route.vollständigerPfad)
    beiAbgeschlossen und beiAbgeschlossen(Route)
  }, beiAbbruch)
}

Funktion pushHash (Pfad) {
  window.location.hash = Pfad
}

Die Methode transitionTo() ist in der übergeordneten Klasse definiert, um die grundlegende Logik von Routenänderungen zu handhaben. Die Methode push() wird hauptsächlich verwendet, um den Hash des Fensters direkt zuzuweisen:

Fenster.Standort.Hash = Route.vollständigerPfad

Änderungen am Hash werden automatisch in die Zugriffshistorie des Browsers eingetragen.

Wie wird die Ansicht aktualisiert? Schauen wir uns die Methode transitionTo() in der übergeordneten Klasse History an:

transitionTo (Standort: Rohstandort, bei Abschluss?: Funktion, bei Abbruch?: Funktion) {
  const route = dieser.router.match(Standort, dieser.aktuell)
  dies.confirmTransition(route, () => {
    dies.updateRoute(route)
    ...
  })
}

updateRoute (Route: Route) {
  
  dies.cb und dies.cb(Route)
  
}

listen (cb: Funktion) {
  dies.cb = cb
}

Wie Sie sehen, wird bei einer Änderung der Route die Methode this.cb in History aufgerufen und die Methode this.cb über History.listen(cb) festgelegt. Als wir zur Klassendefinition von VueRouter zurückkehrten, stellten wir fest, dass sie in der Methode init() festgelegt wurde:

init (app: any /* Vue-Komponenteninstanz */) {
    
  this.apps.push(app)

  Verlauf.listen(route => {
    diese.apps.forEach((app) => {
      app._route = Route
    })
  })
}

Den Kommentaren zufolge ist app eine Vue-Komponenteninstanz, aber wir wissen, dass Vue als progressives Front-End-Framework kein integriertes Routenattribut _route in seiner Komponentendefinition haben sollte. Wenn die Komponente dieses Attribut benötigt, sollte es in das Vue-Objekt an der Stelle eingemischt werden, an der das Plug-In geladen wird, d. h. in der install()-Methode von VueRouter. Überprüfen Sie den Quellcode von install.js, dort gibt es den folgenden Absatz:

Exportfunktion installieren (Vue) {
  
  Vue.mixin({
    vorErstellen () {
      wenn (isDef(this.$options.router)) {
        dieser._router = dieser.$options.router
        dies._router.init(dies)
        Vue.util.defineReactive(dies, '_route', dies._router.history.current)
      }
      registerInstance(dies, dies)
    },
  })
}

Durch die Methode Vue.mixin() wird ein Mixin global registriert, was sich auf jede nach der Registrierung erstellte Vue-Instanz auswirkt. Das Mixin definiert ein responsives _route-Attribut durch Vue.util.defineReactive() im beforeCreate-Hook. Die sogenannte responsive Eigenschaft bedeutet, dass bei einer Änderung des _route-Werts automatisch die render()-Methode der Vue-Instanz aufgerufen wird, um die Ansicht zu aktualisieren.

Zusammenfassend lässt sich sagen, dass der Vorgang vom Festlegen von Routenänderungen bis zum Anzeigen von Updates wie folgt abläuft:

$router.push() --> HashHistory.push() --> History.transitionTo() --> History.updateRoute() --> {app._route = route} --> vm.render()

HashHistory.replace()

Die Methode replace() unterscheidet sich von der Methode push() darin, dass sie die neue Route nicht oben im Zugriffsverlaufsstapel des Browsers hinzufügt, sondern die aktuelle Route ersetzt:

ersetzen (Standort: Rohstandort, bei Abschluss?: Funktion, bei Abbruch?: Funktion) {
  dies.transitionTo(Standort, Route => {
    replaceHash(route.vollständigerPfad)
    beiAbgeschlossen und beiAbgeschlossen(Route)
  }, beiAbbruch)
}
  
Funktion replaceHash (Pfad) {
  const i = Fenster.Standort.href.indexOf('#')
  Fenster.Standort.Ersetzen(
    window.location.href.slice(0, i >= 0 ? i : 0) + '#' + Pfad
  )
}

Es ist ersichtlich, dass seine Implementierungsstruktur grundsätzlich der von push () ähnelt. Der Unterschied besteht darin, dass window.location.hash nicht direkt ein Wert zugewiesen wird, sondern die Methode window.location.replace aufgerufen wird, um die Route zu ersetzen.

Hören Sie auf die Adressleiste

Die oben besprochenen VueRouter.push() und VueRouter.replace() können direkt im Logikcode der Vue-Komponente aufgerufen werden. Darüber hinaus können Benutzer im Browser auch Änderungen an der Route direkt in die Adressleiste des Browsers eingeben. Daher muss VueRouter auch in der Lage sein, Änderungen an der Route in der Adressleiste des Browsers zu überwachen und dasselbe Antwortverhalten wie beim Aufruf über Code zu haben. In HashHistory wird diese Funktion über setupListeners implementiert:

setupListeners() {
  window.addEventListener('hashchange', () => {
    wenn (!ensureSlash()) {
      zurückkehren
    }
    dies.transitionTo(getHash(), route => {
      replaceHash(route.vollständigerPfad)
    })
  })
}

Diese Methode legt das Browserereignis „Hashchange“ als Listener fest und die aufgerufene Funktion ist „replaceHash“, d. h. die direkte Eingabe der Route in die Adressleiste des Browsers entspricht dem Aufruf der Methode „replace ()“ im Code.

HTML5Geschichte

Die Verlaufsschnittstelle ist die vom Browserverlaufsstapel bereitgestellte Schnittstelle. Über Methoden wie back (), forward (), go () usw. können wir die Informationen des Browserverlaufsstapels lesen und verschiedene Sprungvorgänge ausführen.

Ab HTML5 bietet die History-Schnittstelle zwei neue Methoden: pushState() und replaceState(), mit denen wir den Browserverlaufsstapel ändern können:

window.history.pushState(Statusobjekt, Titel, URL)
window.history.replaceState(Statusobjekt, Titel, URL)
  • stateObject: Wenn der Browser in einen neuen Status springt, wird ein popState-Ereignis ausgelöst, das eine Kopie dieses stateObject-Parameters enthält
  • Titel: der Titel des hinzugefügten Datensatzes
  • URL: URL des hinzuzufügenden Datensatzes

Diese beiden Methoden haben eine gemeinsame Funktion: Wenn sie aufgerufen werden, um den Browserverlaufsstapel zu ändern, sendet der Browser, obwohl sich die aktuelle URL geändert hat, nicht sofort eine Anforderung an die URL (der Browser versucht nicht, diese URL nach einem Aufruf von pushState() zu laden). Dies bildet die Grundlage für das Front-End-Routing der Single-Page-Anwendung, um „die Ansicht zu aktualisieren, aber die Seite nicht erneut anzufordern“.

Schauen wir uns den Quellcode im Vue-Router an:

push (Standort: Rohstandort, bei Abschluss?: Funktion, bei Abbruch?: Funktion) {
  const { current: fromRoute } = dies
  dies.transitionTo(Standort, Route => {
    pushState(saubererPfad(diese.Basis + Route.vollständigerPfad))
    handleScroll(dieser.Router, Route, vonRoute, false)
    beiAbgeschlossen und beiAbgeschlossen(Route)
  }, beiAbbruch)
}

ersetzen (Standort: Rohstandort, bei Abschluss?: Funktion, bei Abbruch?: Funktion) {
  const { current: fromRoute } = dies
  dies.transitionTo(Standort, Route => {
    replaceState(cleanPath(diese.Basis + Route.vollständigerPfad))
    handleScroll(dieser.Router, Route, vonRoute, false)
    beiAbgeschlossen und beiAbgeschlossen(Route)
  }, beiAbbruch)
}

// src/util/push-state.js
Exportfunktion pushState (URL?: Zeichenfolge, Ersetzen?: Boolescher Wert) {
  saveScrollPosition()
  // Versuchen Sie, den PushState-Aufruf abzufangen, um Safari zu umgehen
  // DOM-Ausnahme 18, bei der die Anzahl der PushState-Aufrufe auf 100 begrenzt wird
  const history = fenster.history
  versuchen {
    wenn (ersetzen) {
      history.replaceState({ Schlüssel: _key }, '', URL)
    } anders {
      _key = genKey()
      history.pushState({ Schlüssel: _key }, '', URL)
    }
  } fangen (e) {
    window.location[ersetzen? 'ersetzen': 'zuweisen'](URL)
  }
}

Exportfunktion replaceState (URL?: Zeichenfolge) {
  pushState(URL, wahr)
}

Die Codestruktur und Logik zum Aktualisieren von Ansichten ähneln grundsätzlich dem Hash-Modus, mit der Ausnahme, dass die direkte Zuweisung von window.location.hash zu window.location.replace() in den Aufruf der Methoden history.pushState() und history.replaceState() geändert wird.

Das Hinzufügen eines Listeners zum Ändern der URL in der Adressleiste des Browsers in HTML5History wird direkt im Konstruktor ausgeführt:

Konstruktor (Router: Router, Basis: ?string) {
  
  window.addEventListener('popstate', e => {
    const current = dies.aktuell
    dies.transitionTo(getLocation(this.base), Route => {
      wenn (erwarteScrollen) {
        handleScroll(Router, Route, aktuell, wahr)
      }
    })
  })
}

Natürlich verwendet HTML5History neue Funktionen von HTML5, die von einer bestimmten Browserversion unterstützt werden müssen. Wie wir bereits gesehen haben, wird anhand der Variable supportsPushState geprüft, ob der Browser dies unterstützt:

// src/util/push-state.js
export const supportsPushState = inBrowser && (Funktion () {
  const ua = window.navigator.userAgent

  Wenn (
    (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
    ua.indexOf('Mobile Safari') !== -1 &&
    ua.indexOf('Chrome') === -1 &&
    ua.indexOf('Windows Phone') === -1
  ) {
    return false
  }

  gibt window.history und „pushState“ in window.history zurück
})()

Das Obige ist eine Einführung in den Quellcode des Hash-Modus und des Verlaufsmodus. Beide Modi werden über die Browserschnittstelle implementiert. Darüber hinaus bereitet vue-router auch einen abstrakten Modus für Nicht-Browser-Umgebungen vor. Das Prinzip besteht darin, einen Array-Stack zu verwenden, um die Funktion des Browser-Verlaufsstapels zu simulieren. Natürlich handelt es sich bei den oben genannten Punkten nur um einige Kernlogiken. Um die Robustheit des Systems sicherzustellen, enthält der Quellcode viele Hilfslogiken, die ebenfalls erlernt werden sollten. Darüber hinaus gibt es im Vue-Router wichtige Teile wie Routenanpassung und Router-View-Ansichtskomponenten

Vergleich der beiden Modi

In allgemeinen Nachfrageszenarien sind der Hash-Modus und der Verlaufsmodus ähnlich, aber fast alle Artikel empfehlen die Verwendung des Verlaufsmodus. Der Grund ist: Das Symbol "#" ist zu hässlich ... 0_0 "

Wenn wir keine hässlichen Hashes wollen, können wir den History-Modus des Routers verwenden - offizielle Dokumentation

Als gewissenhafte Menschen sollten wir die Qualität einer Technik natürlich nicht anhand des Aussehens beurteilen. Laut MDN hat der Aufruf von history.pushState() gegenüber der direkten Änderung des Hashs folgende Vorteile:

  • Die neue URL, die von pushState gesetzt wird, kann jede beliebige URL mit demselben Ursprung wie die aktuelle URL sein; Hash kann nur den Teil nach # ändern, also kann es nur die URL desselben Dokuments wie das aktuelle setzen
  • Die neue URL, die von pushState gesetzt wird, kann genau dieselbe sein wie die aktuelle URL, wodurch der Datensatz ebenfalls zum Stapel hinzugefügt wird. Der neue Wert, der von hash gesetzt wird, muss sich vom ursprünglichen Wert unterscheiden, um das Hinzufügen des Datensatzes zum Stapel auszulösen.
  • pushState kann über stateObject beliebige Datentypen zum Datensatz hinzufügen, während hash nur kurze Zeichenfolgen hinzufügen kann.
  • pushState kann zusätzlich das Titelattribut für die spätere Verwendung festlegen

Ein Problem mit dem Verlaufsmodus

Wir wissen, dass das ideale Nutzungsszenario für Einzelseitenanwendungen darin besteht, index.html nur beim Aufrufen der Anwendung zu laden und nachfolgende Netzwerkvorgänge über Ajax abzuschließen, ohne die Seite gemäß der URL erneut anzufordern. Es ist jedoch unvermeidlich, auf besondere Situationen zu stoßen, z. B. wenn der Benutzer direkt in die Adressleiste eingibt und die Eingabetaste drückt, der Browser neu startet und die Anwendung neu lädt usw.

Der Hash-Modus ändert nur den Inhalt des Hash-Teils und der Hash-Teil wird nicht in die HTTP-Anforderung aufgenommen:

http://oursite.com/#/user/id // Wenn Sie erneut anfordern, wird nur http://oursite.com/ gesendet

Daher gibt es im Hash-Modus keine Probleme, wenn Seiten basierend auf URLs angefordert werden.

Der Verlaufsmodus ändert die URL so, dass sie mit der URL des normalen Anforderungs-Backends übereinstimmt.

http://oursite.com/user/id

Senden Sie in diesem Fall die Anfrage erneut an das Backend. Wenn das Backend nicht mit der entsprechenden /user/id-Routingverarbeitung konfiguriert ist, wird ein 404-Fehler zurückgegeben. Die offiziell empfohlene Lösung besteht darin, serverseitig eine Kandidatenressource hinzuzufügen, um alle Situationen abzudecken: Wenn die URL keiner statischen Ressource entspricht, sollte dieselbe index.html-Seite zurückgegeben werden, also die Seite, von der Ihre App abhängt. Darüber hinaus gibt der Server auf diese Weise keine 404-Fehlerseite mehr zurück, da für alle Pfade die Datei index.html zurückgegeben wird. Um dies zu vermeiden, decken Sie alle Routing-Situationen in der Vue-Anwendung ab und geben Sie dann eine 404-Seite aus. Wenn Sie alternativ Node.js als Backend verwenden, können Sie das serverseitige Routing zum Abgleichen der URL nutzen und 404 zurückgeben, wenn keine Übereinstimmung mit der Route gefunden wird, und so ein Fallback implementieren.

Anwendungsdateien direkt laden

Tipp: Die erstellten Dateien sollen über einen HTTP-Server bereitgestellt werden.

Das Öffnen von index.html über file:// funktioniert nicht.

Nachdem das Vue-Projekt über das Webpack von Vue-CLI gepackt wurde, wird in der Befehlszeile die folgende Eingabeaufforderung angezeigt. Normalerweise wird auf Front-End-Projekte über den Server zugegriffen, egal ob in der Entwicklung oder online, und es gibt kein „Öffnen von index.html über file://“. Programmierer wissen jedoch alle, dass Anforderungen und Szenarien immer seltsam sind. Es gibt nichts, woran Produktmanager nicht denken können, nur das, woran Sie nicht denken können.

Die ursprüngliche Absicht beim Schreiben dieses Artikels bestand darin, auf folgendes Problem zu stoßen: Ich musste schnell ein mobiles Anzeigeprojekt entwickeln und beschloss, WebView zum Laden der Vue-Einzelseitenanwendung zu verwenden, aber es war kein Backend-Server vorhanden, sodass alle Ressourcen aus dem lokalen Dateisystem geladen werden mussten:

//AndroidAppWrapper
öffentliche Klasse MainActivity erweitert AppCompatActivity {

    private WebView WebView;

    @Überschreiben
    geschützt void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        WebView = neue WebView(diese);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.loadUrl("file:///android_asset/index.html");
        setContentView(webView);
    }

    @Überschreiben
    öffentliches Boolean beiTastennachunten(int Schlüsselcode, Schlüsselereignisereignis) {
        wenn ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
            webView.goBack();
            gibt true zurück;
        }
        gibt false zurück;
    }
}

In diesem Fall muss ich anscheinend "index.html über file:// öffnen", also muss ich zuerst einige Einstellungen vornehmen

  • Ändern Sie in der Projektdatei config.js den Wert des Felds assetPublicPath in den relativen Pfad „./“.
  • Passen Sie den Speicherort statischer Ressourcen wie Bilder im generierten statischen Ordner an, damit er mit der Referenzadresse im Code übereinstimmt.

Dies ist eine offensichtliche Änderung, die vorgenommen werden muss, aber nach der Änderung kann es immer noch nicht erfolgreich geladen werden. Nach wiederholter Untersuchung wurde festgestellt, dass der Router bei der Entwicklung des Projekts auf den Verlaufsmodus eingestellt war (aus ästhetischen Gründen ... 0_0"). Als er in den Hash-Modus geändert wurde, konnte er normal geladen werden.

Warum passiert das? Die Gründe dafür habe ich wie folgt analysiert:

Beim direkten Laden von index.html aus dem Dateisystem lautet die URL:

Datei:///android_asset/index.html

Der Pfad, mit dem die Startseitenansicht übereinstimmen muss, ist der Pfad: '/':

exportiere standardmäßig einen neuen Router({
  Modus: "Verlauf",
  Routen: [
    {
      Weg: '/',
      Name: "Index",
      Komponente: IndexView
    }
  ]
})

Schauen wir uns zunächst den Verlaufsmodus in HTML5History an:

secureURL ( push?: boolean ) {
  wenn (getLocation(diese.Basis) !== dieser.aktuelle.vollständigerPfad) {
    const current = cleanPath(diese.Basis + dies.aktueller.vollerPath)
    pushen? pushState(aktuell) : replaceState(aktuell)
  }
}

Exportfunktion getLocation (Basis: Zeichenfolge): Zeichenfolge {
  let Pfad = Fenster.Standort.Pfadname
  wenn (Basis && Pfad.indexOf(Basis) === 0) {
    Pfad = Pfad.Slice(Basis.Länge)
  }
  return (Pfad || '/') + window.location.search + window.location.hash
}

Die Logik stellt nur sicher, dass die URL existiert. Der Pfad wird direkt aus window.location.pathname durch Abschneiden gewonnen. Er endet mit index.html, kann also nicht mit '/' übereinstimmen, daher funktioniert „index.html über file:// zu öffnen nicht“.

Schauen wir uns den Hash-Modus noch einmal an. In HashHistory:

exportiere Klasse HashHistory erweitert History {
  Konstruktor (Router: Router, Basis: ?string, Fallback: Boolean) {
    ...
    Schrägstrich sicherstellen ()
  }

  // dies wird verzögert, bis die App gemountet ist
  // um zu vermeiden, dass der Hashchange-Listener zu früh ausgelöst wird
  setupListeners() {
    window.addEventListener('hashchange', () => {
      wenn (!ensureSlash()) {
        zurückkehren
      }
      ...
    })
  }

  getAktuellerStandort() {
    returniere getHash()
  }
}

Funktion EnsureSlash (): Boolesch {
  const Pfad = getHash()
  wenn (Pfad.charAt(0) === '/') {
    returniere wahr
  }
  replaceHash('/' + Pfad)
  return false
}

Exportfunktion getHash(): Zeichenfolge {
  const href = fenster.standort.href
  const index = href.indexOf('#')
  Rückgabeindex === -1 ? '' : href.slice(index + 1)
}

Wir können sehen, dass in der Codelogik die Funktion EnsureSlash() oft vorkommt. Wenn auf das Symbol # ein '/' folgt, gibt sie true zurück, andernfalls wird das '/' zwangsweise eingefügt. Daher können wir sehen, dass die URL auch dann die folgende Form annimmt, wenn index.html aus dem Dateisystem geöffnet wird:

file:///C:/Benutzer/dist/index.html#/

Der von der Methode getHash() zurückgegebene Pfad ist „/“, der mit der Route der Home-Ansicht übereinstimmt.

Wenn Sie daher eine Vue-Einzelseitenanwendung ohne die Hilfe eines Backend-Servers direkt aus dem Dateisystem laden möchten, müssen Sie neben einigen Pfadeinstellungen nach dem Verpacken auch sicherstellen, dass der Vue-Router den Hash-Modus verwendet.

Oben sind die Details der beiden Implementierungen des Front-End-Routings aus der Perspektive des Vue-Routers aufgeführt. Weitere Informationen zu den beiden Implementierungen des Vue-Front-End-Routings finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Detaillierte Erklärung der Art und Weise, wie das Front-End-Routing des Vue-Routers Werte weitergibt
  • Zwei Möglichkeiten zum Implementieren von Front-End-Routing im Vue-Router-Quellcode
  • Eine kurze Analyse des Front-End-Routings und des Implementierungsprinzips des Vue-Routers
  • Konfigurieren Sie eine Vue-Router-Frontend-Route im Vue-CLI-Gerüst
  • Die Hook-Funktion von Vue-Router implementiert Routing Guard
  • Vue Router vue-router ausführliche Erklärung Anleitung
  • Detaillierte Erklärung des Unterschieds zwischen Hash-Modus und Verlaufsmodus im Vue-Router
  • vue-router definiert Metadaten-Metaoperationen
  • Erste Praxis von vue3.0+vue-router+element-plus
  • Detaillierte Erklärung des Navigations-Hooks (Navigation Guard) des Vue-Routers

<<:  Lösen Sie das Problem der Verwendung von linuxdeployqt zum Verpacken von Qt-Programmen in Ubuntu

>>:  Probleme und Lösungen beim Bereitstellen eines Projekts beim Upgrade der Mysql-Datenbank von Version 5.6.28 auf Version 8.0.11

Artikel empfehlen

Implementierung von Nginx-Weiterleitungsübereinstimmungsregeln

1. Regulärer Ausdrucksabgleich ~ für Groß- und Kl...

Wissen Sie, wie man Mock in einem Vue-Projekt verwendet?

Inhaltsverzeichnis Erster Schritt: Der zweite Sch...

Eine kurze Diskussion über den Unterschied zwischen src und href in HTML

Einfach ausgedrückt bedeutet src „Ich möchte dies...

Node-Skript realisiert automatische Anmelde- und Lotteriefunktion

Inhaltsverzeichnis 1. Einleitung 2. Vorbereitung ...

So löschen Sie den MySQL 8.0-Dienst vollständig unter Linux

Bevor Sie diesen Artikel lesen, sollten Sie sich ...

TypeScript-Union-Typen, Schnittmengentypen und Typwächter

Inhaltsverzeichnis 1. Union-Typ 2. Crossover-Typ ...

Erste Schritte Tutorial für Anfänger: Domänennamenauflösung und Bindung

Wie können Sie also nach der Registrierung eines ...

Sechs wichtige Selektoren in CSS (merken Sie sie sich in drei Sekunden)

Von: https://blog.csdn.net/qq_44761243/article/de...

Detaillierte Erläuterung der MySQL-Datumszeichenfolgen-Zeitstempelkonvertierung

Die Konvertierung zwischen Zeit, Zeichenfolge und...

Konfigurationsmethode für das Nginx-Anforderungslimit

Nginx ist ein leistungsstarker, leistungsstarker ...

Detaillierte Untersuchung der MySQL-Mehrversions-Parallelitätskontrolle MVCC

MVCC MVCC (Multi-Version Concurrency Control) ist...