Zusammenfassung häufiger Probleme und Lösungen in Vue (empfohlen)

Zusammenfassung häufiger Probleme und Lösungen in Vue (empfohlen)

Es gibt einige Probleme, die nicht auf Vue beschränkt sind, sondern auch für andere Arten von SPA-Projekten gelten.

1. Seitenberechtigungskontrolle und Seitenberechtigungskontrolle zur Anmeldeüberprüfung

Was bedeutet Seitenberechtigungskontrolle?

Das heißt, eine Website hat unterschiedliche Rollen, etwa Administratoren und normale Benutzer, und für den Zugriff auf unterschiedliche Seiten sind unterschiedliche Rollen erforderlich. Wenn eine Rolle unbefugten Zugriff auf eine Seite hat, müssen Einschränkungen auferlegt werden.

Eine Möglichkeit besteht darin, dies durch dynamisches Hinzufügen von Routen und Menüs zu steuern. Nicht zugängliche Seiten werden nicht zur Routing-Tabelle hinzugefügt. Dies ist eine der Möglichkeiten. Weitere Einzelheiten finden Sie im nächsten Abschnitt „Dynamisches Menü“.

Eine andere Möglichkeit besteht darin, alle Seiten in die Routing-Tabelle einzutragen, beim Zugriff jedoch nur die Rollenberechtigungen zu beurteilen. Wenn Sie die Berechtigung haben, wird der Zugriff gestattet. Wenn Sie keine Berechtigung haben, wird der Zugriff verweigert und die Anfrage wird auf die 404-Seite umgeleitet.

Ideen

Fügen Sie im Metaattribut jeder Route den Rollen die Rollen hinzu, die auf die Route zugreifen können. Nach der Anmeldung jedes Benutzers wird seine Rolle zurückgegeben. Beim Aufrufen der Seite wird dann das Metaattribut der Route mit der Rolle des Benutzers verglichen. Wenn die Rolle des Benutzers in den Rollen der Route enthalten ist, wird der Zugriff erlaubt. Wenn nicht, wird der Zugriff verweigert.

Codebeispiel

Routeninformationen

Routen: [
 {
 Pfad: '/login',
 Name: 'Anmelden',
 Meta: {
 Rollen: ['Administrator', 'Benutzer']
 },
 Komponente: () => import('../Komponenten/Login.vue')
 },
 {
 Pfad: 'Home',
 Name: 'Heimat',
 Meta: {
 Rollen: ['admin']
 },
 Komponente: () => import('../views/Home.vue')
 },
]

Seitensteuerung

// Angenommen, es gibt zwei Rollen: Administrator und Benutzer
//Hier ist die vom Hintergrund erhaltene Benutzerrolle const role = 'user'
// Das Ereignis router.beforeEach wird vor dem Aufrufen einer Seite ausgelöst router.beforeEach((to, from, next) => {
 wenn (to.meta.roles.includes(Rolle)) {
 nächste()
 } anders {
 weiter({Pfad: '/404'})
 }
})

Anmeldeüberprüfung

Wenn Sie sich einmal bei einer Website angemeldet haben, können Sie im Allgemeinen direkt auf andere Seiten der Website zugreifen, ohne sich erneut anmelden zu müssen. Dies können wir über Token oder Cookies tun. Der folgende Code zeigt, wie man Token zur Steuerung der Anmeldeüberprüfung verwendet.

router.beforeEach((bis, von, weiter) => {
 // Wenn ein Token vorhanden ist, bedeutet dies, dass der Benutzer sich angemeldet hat. if (localStorage.getItem('token')) {
 // Wenn Sie angemeldet sind, werden Sie beim Zugriff auf die Anmeldeseite auf die Startseite weitergeleitet, if (to.path === '/login') {
 weiter({Pfad: '/'})
 } anders {
 weiter({Pfad: zu.Pfad || '/'})
 }
 } anders {
 // Wenn Sie nicht angemeldet sind, wird jede von Ihnen besuchte Seite auf die Anmeldeseite umgeleitet, if (to.path === '/login') {
 nächste()
 } anders {
 weiter(`/login?redirect=${to.path}`)
 }
 }
})

2. Dynamisches Menü

Beim Schreiben eines Backend-Verwaltungssystems sind schätzungsweise viele Leute auf eine solche Anforderung gestoßen: das dynamische Hinzufügen von Routen und Menüs basierend auf Hintergrunddaten. Warum das tun? Da verschiedene Benutzer über unterschiedliche Berechtigungen verfügen, können sie auf unterschiedliche Seiten zugreifen.

Dynamisches Hinzufügen von Routen

Routen können dynamisch mit der Methode addRoutes des Vue-Routers hinzugefügt werden.

Schauen wir uns zunächst die offizielle Einführung an:

router.addRoutes

router.addRoutes(routes: Array<Routenkonfiguration>)

Fügen Sie dynamisch weitere Routingregeln hinzu. Das Argument muss ein Array sein, das routes Anforderungen der Routenoption entspricht.

Zum Beispiel:

const router = neuer Router({
 Routen: [
 {
  Pfad: '/login',
  Name: 'Anmelden',
  Komponente: () => import('../Komponenten/Login.vue')
 },
 {Pfad: '/', Umleitung: '/home'},
 ] 
})

Der obige Code hat die gleiche Wirkung wie der folgende Code

const router = neuer Router({
 Routen: [
 {Pfad: '/', Umleitung: '/home'},
 ] 
})

router.addRoutes([
 {
 Pfad: '/login',
 Name: 'Anmelden',
 Komponente: () => import('../Komponenten/Login.vue')
 }
])

Wenn beim dynamischen Hinzufügen von Routen eine 404-Seite vorhanden ist, muss diese zuletzt hinzugefügt werden. Andernfalls erfolgt nach dem Hinzufügen der Seite während der Anmeldung eine Weiterleitung auf die 404-Seite.

Ähnlich muss auch diese Regel zuletzt hinzugefügt werden.

{Pfad: '*', Umleitung: '/404'}

Dynamisch generiertes Menü

Nehmen wir an, dass die vom Hintergrund zurückgegebenen Daten folgendermaßen aussehen:

// Daten der linken Menüleiste menuItems: [
 {
 Name: „home“, // Der Name der Route, zu der gesprungen werden soll, entspricht nicht dem Pfad. Größe: 18, // Symbolgröße Typ: „md-home“, // Symboltyp Text: „Homepage“ // Textinhalt },
 {
 Text: 'Sekundäres Menü',
 Typ: 'ios-paper',
 Kinder: [
  {
  Typ: „ios-grid“,
  Name: "t1",
  Text: 'Tabelle'
  },
  {
  Text: 'Menü Ebene 3',
  Typ: 'ios-paper',
  Kinder: [
   {
   Typ: „iOS-Benachrichtigungsübersicht“,
   Name: "Nachricht",
   Text: „Nachricht anzeigen“
   },
  ]
  }
 ]
 }
]

Sehen wir uns an, wie man es in eine Menüleiste umwandelt. Ich habe hier die iview-Komponente verwendet, um das Rad nicht neu erfinden zu müssen.

<!-- Menüleiste -->
<Menü ref="Seitenmenü" Thema="dunkel" Breite="100%" @on-select="gotoPage" 
Akkordeon :open-names="offeneMenüs" :active-name="aktuelleSeite" @on-open-change="Menüänderung">
 <!-- Dynamisches Menü -->
 <div v-for="(Element, Index) in Menüelementen" :key="index">
 <Untermenü v-if="item.children" :name="index">
  <Vorlagenslot="Titel">
  <Symbol :size="Artikelgröße" :typ="Artikeltyp"/>
  <span v-show="isShowAsideTitle">{{item.text}}</span>
  </Vorlage>
  <div v-for="(Unterelement, i) in Element.Kinder" :Schlüssel="Index + i">
  <Untermenü v-if="Unterelement.Kinder" :name="index + '-' + i">
   <Vorlagenslot="Titel">
   <Symbol :size="Unterelement.size" :type="Unterelement.type"/>
   <span v-show="isShowAsideTitle">{{subItem.text}}</span>
   </Vorlage>
   <MenuItem-Klasse="Menüebene 3" v-für="(threeItem, k) in subItem.children" :name="threeItem.name" :key="index + i + k">
   <Symbol :size="dreiElement.size" :type="dreiElement.type"/>
   <span v-show="isShowAsideTitle">{{threeItem.text}}</span>
   </Menüpunkt>
  </Untermenü>
  <Menüelement v-else v-show="isShowAsideTitle" :name="unterelement.name">
   <Symbol :size="Unterelement.size" :type="Unterelement.type"/>
   <span v-show="isShowAsideTitle">{{subItem.text}}</span>
  </Menüpunkt>
  </div>
 </Untermenü>
 <Menüelement v-else :name="element.name">
  <Symbol :Größe="Artikelgröße" :Typ="Artikeltyp" />
  <span v-show="isShowAsideTitle">{{item.text}}</span>
 </Menüpunkt>
 </div>
</Menü>

Sie müssen sich den Code nicht allzu genau ansehen, sondern nur das Prinzip verstehen. Tatsächlich durchläuft das Unterarray lediglich dreimal v-for, um ein dreistufiges Menü zu generieren.

Dieses dynamische Menü hat jedoch einen Fehler: Es unterstützt nur dreistufige Menüs. Ein besserer Ansatz besteht darin, den Prozess der Menügenerierung in einer Komponente zu kapseln und diese dann rekursiv aufzurufen, sodass eine unbegrenzte Anzahl von Menüs unterstützt werden kann. Beim Erstellen eines Menüs müssen Sie feststellen, ob Untermenüs vorhanden sind. Wenn ja, rufen Sie die Komponente rekursiv auf.

Wie oben erwähnt, wird dynamisches Routing mithilfe von addRoutes implementiert. Sehen wir uns nun an, wie es im Einzelnen funktioniert.

Listen Sie zunächst alle Seitenrouten des Projekts auf und verwenden Sie dann die vom Hintergrund zurückgegebenen Daten, um sie dynamisch abzugleichen. Wenn eine Übereinstimmung vorliegt, fügen Sie die Route hinzu, andernfalls fügen Sie sie nicht hinzu. Abschließend fügen Sie die neu generierten Routing-Daten mittels addRoutes der Routing-Tabelle hinzu.

const asyncRoutes = {
 'heim': {
 Pfad: 'Home',
 Name: 'Heimat',
 Komponente: () => import('../views/Home.vue')
 },
 't1': {
 Pfad: 't1',
 Name: "t1",
 Komponente: () => import('../views/T1.vue')
 },
 'Passwort': {
 Pfad: 'Passwort',
 Name: 'Passwort',
 Komponente: () => import('../views/Password.vue')
 },
 'Nachricht': {
 Pfad: 'msg',
 Name: "Nachricht",
 Komponente: () => import('../views/Msg.vue')
 },
 'Benutzerinfo': {
 Pfad: 'Benutzerinfo',
 Name: 'Benutzerinfo',
 Komponente: () => import('../views/UserInfo.vue')
 }
}

// Übergeben Sie Hintergrunddaten, um die Routing-Tabelle zu generieren menusToRoutes(menusData)

// Menüinformationen in entsprechende Routeninformationen umwandeln und dynamisch hinzufügen function menusToRoutes(data) {
 const Ergebnis = []
 const Kinder = []

 Ergebnis.push({
 Weg: '/',
 Komponente: () => import('../Komponenten/Index.vue'),
 Kinder,
 })

 Daten.fürJeden(Element => {
 Routes generieren(untergeordnete Elemente, Element)
 })

 Kinder.push({
 Pfad: 'Fehler',
 Name: 'Fehler',
 Komponente: () => import('../Komponenten/Error.vue')
 })

 // Zum Schluss noch die 404-Seite hinzufügen, sonst wird nach erfolgreichem Login auf die 404-Seite gesprungen result.push(
 {Pfad: '*', Umleitung: '/Fehler'},
 )

 Ergebnis zurückgeben
}

Funktion generateRoutes(Kinder, Element) {
 wenn (Artikelname) {
 Kinder.push(asyncRoutes[item.name])
 } sonst wenn (Element.Kinder) {
 item.children.forEach(e => {
  Routes generieren(Kinder, e)
 })
 }
}

Die Codeimplementierung des dynamischen Menüs befindet sich auf GitHub in den Dateien src/components/Index.vue , src/permission.js und src/utils/index.js dieses Projekts.

3. Vorwärts aktualisiert, rückwärts nicht. Anforderung 1:

Beim ersten Aufrufen einer Listenseite erfolgt eine Aufforderung zur Datenerfassung.

Wenn Sie auf ein Listenelement klicken, zur Detailseite springen und dann von der Detailseite zur Listenseite zurückkehren, wird die Seite nicht aktualisiert.

Das heißt, wenn Sie die Listenseite von anderen Seiten aus aufrufen, müssen Sie aktualisieren, um Daten abzurufen, und Sie dürfen nicht aktualisieren, wenn Sie von der Detailseite aus zur Listenseite zurückkehren.

Lösung

Im App.vue-Setup:

 <keep-alive include="Liste">
  <Router-Ansicht/>
 </am Leben erhalten>

Angenommen, die Listenseite ist list.vue und die Detailseite ist detail.vue. Beides sind Unterkomponenten.

Wir fügen den Namen der Listenseite in Keep-Alive ein und speichern die Listenseite im Cache.

Fügen Sie dann in der Erstellungsfunktion der Listenseite eine Ajax-Anforderung hinzu, sodass Daten nur beim ersten Aufrufen der Listenseite angefordert werden. Beim Springen von der Listenseite zur Detailseite und dann von der Detailseite zurück wird die Listenseite nicht aktualisiert. Dadurch wird das Problem gelöst.

Anforderung 2:

Auf der Grundlage der ersten Anforderung wird eine weitere Anforderung hinzugefügt: Das entsprechende Listenelement kann auf der Detailseite gelöscht werden. Zu diesem Zeitpunkt ist es beim Zurückkehren zur Listenseite erforderlich, die Daten zu aktualisieren und erneut abzurufen.

Wir können in der Routing-Konfigurationsdatei ein Metaattribut zu detail.vue hinzufügen.

 {
  Pfad: '/detail',
  Name: "Detail",
  Komponente: () => import('../view/detail.vue'),
  Meta: {isRefresh: true}
 },

Dieses Metaattribut kann auf der Detailseite über this.$route.meta.isRefresh gelesen und festgelegt werden.

Nachdem Sie diese Eigenschaft festgelegt haben, müssen Sie auch die Eigenschaft „watch $route“ in der Datei App.vue festlegen.

 betrachten:
 $route(nach, von) {
  const fname = von.name
  const tname = bis.name
  wenn (from.meta.isRefresh || (fname != 'detail' && tname == 'list')) {
  from.meta.isRefresh = false
 // Daten hier erneut anfordern}
 }
 },

Auf diese Weise muss in der Erstellungsfunktion der Listenseite kein Ajax zum Anfordern von Daten verwendet werden, und die gesamte Verarbeitung kann in App.vue erfolgen.

Es gibt zwei Bedingungen zum Auslösen der Anforderungsdaten:

Wenn die Liste von anderen Seiten (außer der Detailseite) stammt, müssen Daten angefordert werden. Wenn Sie von der Detailseite zur Listenseite zurückkehren und „isRefresh“ im Metaattribut der Detailseite „true“ ist, müssen Sie die Daten auch erneut anfordern.

Wenn wir das entsprechende Listenelement auf der Detailseite löschen, können wir isRefresh im Metaattribut der Detailseite auf true setzen. Kehren Sie jetzt zur Listenseite zurück und die Seite wird aktualisiert.

Lösung 2

Für Anforderung 2 gibt es tatsächlich eine einfachere Lösung, nämlich die Verwendung key Schlüsselattributs der Router-Ansicht.

<am Leben erhalten>
 <router-view :key="$route.fullPath"/>
</am Leben erhalten>

Erstens ermöglicht Keep-Alive das Zwischenspeichern aller Seiten. Wenn Sie eine bestimmte Routenseite nicht zwischenspeichern und neu laden möchten, können Sie beim Springen eine zufällige Zeichenfolge übergeben, damit sie neu geladen werden kann. Wenn Sie beispielsweise von der Listenseite aus auf die Detailseite gehen und dann eine Option auf der Listenseite löschen, müssen Sie aktualisieren, wenn Sie von der Detailseite aus zur Listenseite zurückkehren. Wir können folgendermaßen springen:

dies.$router.push({
 Pfad: '/list',
 Abfrage: { 'randomID': 'id' + Math.random() },
})

Diese Lösung ist relativ einfacher.

4. Laden bei Mehrfachanfragen anzeigen und schließen

Im Allgemeinen wird in Vue der Interceptor von Axios verwendet, um die Anzeige und das Schließen des Ladevorgangs wie folgt zu steuern:

Konfigurieren Sie einen globalen Loader in App.vue.

 <div Klasse="App">
  <keep-alive :include="keepAliveData">
   <Router-Ansicht/>
  </am Leben erhalten>
  <div Klasse="wird geladen" v-show="isShowLoading">
   <Spin-Größe="groß"></Spin>
  </div>
 </div>

Richten Sie auch den Axios-Interceptor ein.

 // Anforderungs-Interceptor hinzufügen this.$axios.interceptors.request.use(config => {
  this.isShowLoading = true
  Konfiguration zurückgeben
 }, Fehler => {
  this.isShowLoading = false
  returniere Promise.reject(Fehler)
 })

 // Antwort-Interceptor hinzufügen this.$axios.interceptors.response.use(response => {
  this.isShowLoading = false
  Antwort zurückgeben
 }, Fehler => {
  this.isShowLoading = false
  returniere Promise.reject(Fehler)
 })

Die Funktion dieses Interceptors besteht darin, das Laden vor der Anforderung einzuschalten und das Laden auszuschalten, wenn die Anforderung endet oder ein Fehler auftritt.

Dies funktioniert einwandfrei, wenn jeweils nur eine Anfrage vorliegt. Bei mehreren gleichzeitigen Anfragen kommt es allerdings zu Problemen.

Beispiel:

Wenn zwei Anfragen gleichzeitig initiiert werden, wird vor der Anfrage der Interceptor this.isShowLoading = true aktiviert und das Laden eingeschaltet.

Jetzt ist eine Anfrage geschlossen. this.isShowLoading = false Interceptor schaltet das Laden ab, aber die andere Anfrage wird aus irgendeinem Grund nicht beendet.

Die Folge ist, dass die Seitenanforderung nicht abgeschlossen wurde, das Laden jedoch deaktiviert ist. Der Benutzer wird denken, dass das Laden der Seite abgeschlossen wurde. Infolgedessen kann die Seite nicht normal ausgeführt werden, was zu einer schlechten Benutzererfahrung führt.

Lösung

Fügen Sie eine „loadingCount“-Variable hinzu, um die Anzahl der Anfragen zu zählen.

Ladeanzahl: 0

Fügen Sie zwei weitere Methoden hinzu, um loadingCount zu erhöhen und zu verringern.

 Methoden: {
  hinzufügenLaden() {
   this.isShowLoading = true
   dies.loadingCount++
  },

  isCloseLoading() {
   this.loadingCount--
   wenn (this.loadingCount == 0) {
    this.isShowLoading = false
   }
  }
 }

Nun sieht der Interceptor folgendermaßen aus:

  // Anforderungs-Interceptor hinzufügen this.$axios.interceptors.request.use(config => {
   dies.addLoading()
   Konfiguration zurückgeben
  }, Fehler => {
   this.isShowLoading = false
   this.loadingCount = 0
   this.$Message.error('Netzwerkausnahme, bitte versuchen Sie es später erneut')
   returniere Promise.reject(Fehler)
  })

  // Antwort-Interceptor hinzufügen this.$axios.interceptors.response.use(response => {
   dies.isCloseLoading()
   Antwort zurückgeben
  }, Fehler => {
   this.isShowLoading = false
   this.loadingCount = 0
   this.$Message.error('Netzwerkausnahme, bitte versuchen Sie es später erneut')
   returniere Promise.reject(Fehler)
  })

Die Funktionen dieses Abfangjägers sind:

Bei jeder initiierten Anforderung wird das Laden eingeschaltet und loadingCount um 1 erhöht.

Bei jedem Ende einer Anfrage wird loadingCount um 1 reduziert und es wird ermittelt, ob loadingCount 0 ist. Wenn es 0 ist, wird der Ladevorgang beendet.

Dadurch kann das Problem gelöst werden, dass eine der Mehrfachanforderungen vorzeitig beendet wird und dadurch der Ladevorgang beendet wird.

5. Formulardruck

Die zum Drucken benötigte Komponente ist print-js

Normaler Formulardruck

Zum allgemeinen Tabellendruck können Sie einfach den von der Komponente bereitgestellten Beispielen folgen.

druckenJS({
 druckbar: ID, // DOM-ID
 Typ: "html",
 scanStyles: falsch,
})

Drucken von Element-UI-Tabellen (dasselbe gilt für Tabellen in anderen Komponentenbibliotheken)

Die Element-UI-Tabelle scheint eine einzige Tabelle zu sein, besteht aber tatsächlich aus zwei Tabellen.

Die Kopfzeile ist eine Tabelle und der Textkörper eine weitere Tabelle, was zu einem Problem führt: Der Textkörper und die Kopfzeile werden beim Drucken falsch ausgerichtet.

Wenn außerdem in der Tabelle ein Bildlaufbalken angezeigt wird, führt dies ebenfalls zu einer Fehlausrichtung.

Lösung

Meine Idee ist, die beiden Tabellen zu einer Tabelle zu kombinieren. Wenn die print-js-Komponente druckt, extrahiert sie tatsächlich den Inhalt im DOM, der der ID entspricht, und druckt ihn. Daher können Sie vor der Übergabe der ID den Tabelleninhalt, in dem sich die Kopfzeile befindet, extrahieren und in die zweite Tabelle einfügen, um die beiden Tabellen zusammenzuführen. Zu diesem Zeitpunkt tritt beim Drucken kein Ausrichtungsproblem auf.

Funktion printHTML(id) {
 const html = document.querySelector('#' + id).innerHTML
 //Erstelle ein neues DOM
 const div = Dokument.createElement('div')
 const printDOMID = "printDOMElement"
 div.id = druckeDOMID
 div.innerHTML = html

 // Extrahiere den Inhalt der ersten Tabelle, also die Kopfzeile const ths = div.querySelectorAll('.el-table__header-wrapper th')
 const ThsTextArry = []
 für (sei i = 0, len = diese.Länge; i < len; i++) {
  wenn (ths[i].innerText !== '') ThsTextArry.push(ths[i].innerText)
 }

 // Löschen Sie den zusätzlichen Header div.querySelector('.hidden-columns').remove()
 // Der Inhalt der ersten Tabelle ist nach der Extraktion nicht mehr nützlich. Löschen Sie div.querySelector('.el-table__header-wrapper').remove()

 // Füge den Inhalt der ersten Tabelle in die zweite Tabelle ein let newHTML = '<tr>'
 für (lass i = 0, len = ThsTextArry.length; i < len; i++) {
  neuesHTML += '<td style="text-align: center; font-weight: bold">' + ThsTextArry[i] + '</td>'
 }

 neuesHTML += '</tr>'
 div.querySelector('.el-table__body-wrapper table').insertAdjacentHTML('afterbegin', neuesHTML)
 // Fügen Sie der Seite das neue DIV hinzu und löschen Sie es dann nach dem Drucken document.querySelector('body').appendChild(div)
 
 druckenJS({
  druckbar: printDOMID,
  Typ: "html",
  scanStyles: falsch,
  Stil: 'Tabelle { border-collapse: collapse }' // Tabellenstil})

 div.entfernen()
}

6. Laden Sie die Binärdatei herunter

Normalerweise gibt es zwei Möglichkeiten, Dateien auf dem Frontend herunterzuladen. Eine besteht darin, im Hintergrund eine URL bereitzustellen und sie dann mit window.open(URL) herunterzuladen. Bei der anderen Möglichkeit gibt der Hintergrund den Binärinhalt der Datei direkt zurück und das Frontend konvertiert ihn dann vor dem Herunterladen.

Da die erste Methode relativ einfach ist, wird sie hier nicht näher erläutert. In diesem Artikel wird hauptsächlich die Implementierung der zweiten Methode erläutert.

Die zweite Methode erfordert die Verwendung eines Blob-Objekts, das in der MDN-Dokumentation wie folgt beschrieben wird:

Ein Blob-Objekt stellt ein unveränderliches, rohes dateiähnliches Objekt dar. Blob stellt Daten nicht unbedingt im nativen JavaScript-Format dar

Spezifische Verwendung

axios({
 Methode: 'post',
 URL: „/export“,
})
.then(res => {
 // Angenommen, Daten sind die zurückgegebenen Binärdaten const data = res.data
 const url = window.URL.createObjectURL(neuer Blob([Daten], {Typ: "Anwendung/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}))
 const link = document.createElement('a')
 link.style.display = "keine"
 link.href = URL
 link.setAttribute('herunterladen', 'excel.xlsx')
 Dokument.Body.AnhängenKind(Link)
 link.klick()
 Dokument.Body.RemoveChild(Link)
})

Öffnen Sie die heruntergeladene Datei, um zu sehen, ob das Ergebnis korrekt ist.

Alles nur Unsinn...

Irgendetwas muss nicht stimmen.

Schließlich stellte sich heraus, dass das Problem beim Parameter responseType lag, der den Datentyp der Serverantwort angibt. Da es sich bei den vom Backend zurückgegebenen Daten um Binärdaten handelt, müssen wir sie auf Arraybuffer setzen und dann prüfen, ob das Ergebnis korrekt ist.

axios({
 Methode: 'post',
 URL: „/export“,
 Antworttyp: "Array-Puffer",
})
.then(res => {
 // Angenommen, Daten sind die zurückgegebenen Binärdaten const data = res.data
 const url = window.URL.createObjectURL(neuer Blob([Daten], {Typ: "Anwendung/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}))
 const link = document.createElement('a')
 link.style.display = "keine"
 link.href = URL
 link.setAttribute('herunterladen', 'excel.xlsx')
 Dokument.Body.AnhängenKind(Link)
 link.klick()
 Dokument.Body.RemoveChild(Link)
}) 

Diesmal gibt es kein Problem, die Datei kann normal geöffnet werden und der Inhalt ist auch normal, nicht mehr verstümmelt.

Entscheiden Sie, ob die Datei basierend auf dem Inhalt der Hintergrundoberfläche heruntergeladen werden soll

Das Projekt des Autors umfasst eine große Anzahl von Seiten, für die Dateien heruntergeladen werden müssen, und diese Anforderung ist etwas ungewöhnlich.

Die konkreten Anforderungen sind wie folgt

  • Wenn die Anzahl der Datenelemente in der heruntergeladenen Datei den Anforderungen entspricht, wird sie normal heruntergeladen (das Download-Datenlimit ist für jede Seite unterschiedlich und kann daher nicht im Front-End fest codiert werden).
  • Wenn die Datei zu groß ist, gibt das Backend { code: 199999, msg: ‚Die Datei ist zu groß, bitte setzen Sie die Abfrageelemente zurück‘, data: null } zurück, und anschließend meldet das Frontend einen Fehler.

Lassen Sie es uns zuerst analysieren. Zunächst einmal wissen wir gemäß dem Obigen alle, dass der Schnittstellenantwortdatentyp zum Herunterladen von Dateien Arraybuffer ist. Unabhängig davon, ob es sich bei den zurückgegebenen Daten um eine Binärdatei oder eine JSON-Zeichenfolge handelt, empfängt das Front-End tatsächlich einen Array-Puffer. Daher müssen wir den Inhalt des Array-Puffers beurteilen, ihn beim Empfangen von Daten in eine Zeichenfolge konvertieren und prüfen, ob der Code 199999 vorhanden ist. Wenn dies der Fall ist, wird eine Fehlermeldung ausgegeben. Wenn nicht, handelt es sich um eine normale Datei und kann heruntergeladen werden. Die konkrete Umsetzung sieht wie folgt aus:

xios.interceptors.response.use(Antwort => {
  const res = antwort.daten
  // Bestimmen Sie, ob der Antwortdatentyp ArrayBuffer ist. „true“ ist die Schnittstelle zum Herunterladen von Dateien, „false“ ist die normale Schnittstelle, if (res instanceof ArrayBuffer) {
    const utf8decoder = neuer TextDecoder()
    const u8arr = neues Uint8Array(res)
    // Binärdaten in Zeichenfolge umwandeln const temp = utf8decoder.decode(u8arr)
    wenn (temp.includes('{code:199999')) {
      Nachricht({
       // String in JSON-Objektnachricht konvertieren: JSON.parse(temp).msg,
        Typ: "Fehler",
        Dauer: 5000,
      })

      returniere Promise.reject()
    }
  }
  // Normale Typschnittstelle, Code ausgelassen …
  Rückgabewert
}, (Fehler) => {
  // Code ausgelassen...
  returniere Promise.reject(Fehler)
})

7. Console.log-Anweisungen automatisch ignorieren

Exportfunktion rewirteLog() {
  console.log = (Funktion (Protokoll) {
    Rückgabe process.env.NODE_ENV == 'Entwicklung'? log : function() {}
  }(Konsole.log))
}

Importieren Sie diese Funktion in main.js und führen Sie sie einmal aus, um die console.log-Anweisung zu ignorieren.

Zusammenfassen

Dies ist das Ende dieses Artikels über häufige Probleme und Lösungen in Vue. Weitere verwandte Vue-FAQs finden Sie in früheren Artikeln auf 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:
  • Zusammenfassung und Untersuchung einiger häufiger Probleme bei der Verwendung von Vue2.0
  • Vue Router implementiert dynamisches Routing sowie allgemeine Probleme und Lösungen
  • Häufige Probleme und Lösungen in Vue-Projekten (empfohlen)
  • Zusammenfassung der ersten Schritte des VUE-Projekts und häufige Probleme
  • Implementierungsprozess und häufige Probleme im Zusammenhang mit WeChat JSAPI und externer H5-Zahlung im Front-End des Vue-Projekts
  • Zusammenfassung häufiger Probleme und Lösungen bei der Vue-Projektentwicklung
  • Vue-Optimierung: Häufige Speicherleckprobleme und Optimierungsdetails
  • Sprechen Sie über die Erstellung von Vue-Projekten von Grund auf und über häufig auftretende Probleme.

<<:  So fügen Sie eine Festplatte in Vmware hinzu: Erweitern Sie die Festplatte

>>:  Detailliertes Beispiel einer MySQL-Austauschpartition

Artikel empfehlen

Vergleich der Vorteile von vue3 und vue2

Inhaltsverzeichnis Vorteil 1: Optimierung des Dif...

Installation und Konfiguration von MySQL 8.0.15 unter Centos7

In diesem Artikel finden Sie das grafische Tutori...

Detaillierte Erklärung zur Verwendung von Rastereigenschaften in CSS

Rasterlayout Dem übergeordneten Element hinzugefü...

5 Tipps zum Schutz Ihres MySQL Data Warehouse

Durch die Aggregierung von Daten aus verschiedene...

Detaillierte Erklärung zur Verwendung von MySQL mysqldump

1. Einführung in mysqldump mysqldump ist ein logi...

Über Tomcat kombiniert mit Atomikos zur Implementierung von JTA

Vor Kurzem hat das Projekt die Umgebung gewechsel...

Beispiel für einen reinen CSS3-Mindmap-Stil

Mindmap Er sieht wahrscheinlich so aus: Die meist...

Die neuesten 36 hochwertigen kostenlosen englischen Schriftarten freigegeben

01. Unendlichkeit Schriftart herunterladen 02. Ban...

Detaillierter Installationsprozess und Konfiguration von mysql5.7.19 zip

Offizielle Version von MySQL v5.7.19 (32/64-Bit-I...

Perfekte Lösung für keine rc.local-Datei in Linux

Neuere Linux-Distributionen verfügen nicht mehr ü...

Warum der Befehl „explain“ MySQL-Daten ändern kann

Wenn Sie jemand fragen würde, ob die Ausführung v...

Eine kurze Diskussion über bedingte Kodierung und Seitenlayout der VUE-Uni-App

Inhaltsverzeichnis Bedingte Kompilierung Seitenla...

Zusammenfassung der neuen Verwendung von vi (vim) unter Linux

Ich benutze den vi-Editor seit mehreren Jahren, h...

Standardmäßige Stilanordnung für HTML-Tags

html, address,blockquote,body, dd, div,dl, dt, fie...