So navigieren Sie mit dem Vue-Router über Vuex-Aktionen


76

Ich erstelle eine Web-App mit Vue 2.x und Vuex 2.x. Ich rufe einige Informationen von einem entfernten Standort über einen http-Aufruf ab. Wenn dieser Aufruf fehlschlägt, sollte ich auf eine andere Seite umleiten.

GET_PETS: (state) => {
  return $http.get('pets/').then((response)=>{
      state.commit('SET_PETS', response.data)
    })
  },
  error => {this.$router.push({path:"/"}) }
  )
}

Aber this.$router.push({path:"/"})gibt mir folgenden Fehler.

Nicht gefangen (im Versprechen) TypeError: Die Eigenschaft 'push' von undefined kann nicht gelesen werden

Wie kann dies erreicht werden?

Simulierte JsFiddle: hier


Dies liegt daran, dass Sie es in einer Pfeilfunktion verwenden, die 'this' als Literal behandelt. Konvertieren Sie es entweder in eine reguläre Funktion oder verwenden Sie die unten vorgeschlagenen Antworten ...
EldadT

Antworten:



15

Dieses Beispiel kann Ihnen helfen.

main.js

import Vue from "vue";
import VueRouter from "vue-router";

...

Vue.use(VueRouter);

export const router = new VueRouter({
    mode: 'hash',
    base: "./",
    routes: [
        { path: "/", component: welcome},
        { path: "/welcome", component: welcome},

    ]
})

action.js

import {router} from "../main.js"

export const someAction = ({commit}) => {

    router.push("/welcome");
} 

So sollten Sie Vue nicht verwenden. Aktionen sollten keine Nebenwirkungen haben. Lösen Sie dies in Methoden der Komponente wiedispatch('someAction').then(() => this.$router.push('/welcome'))
Adriaan

2
@adriaan nicht unbedingt wahr, auch die Aktionen in den Vuex-Demos haben Nebenwirkungen.
Blowsie

11

Es sieht so aus, als würden Sie Ihren Router nicht in Ihre App einfügen, daher ist er "undefiniert".

In früheren Versionen von vue-router haben Sie: Vue.use(VueRouter)Mit 2.0 können Sie den Router wie folgt in die App einfügen:

const routes = [
  { path: '/foo', component: Foo },
]

const router = new VueRouter({
  routes
})

const app = new Vue({
  router // inject the router
}).$mount('#app')

Dies sollte es dann wie this.$routerin der gesamten App verfügbar machen


Nach Beantwortung einer verwandten Frage: Wie verwende ich den Vue Router aus dem Vuex-Status? Es scheint, dass Vuex die Router-Instanz bei nicht empfängt this.$router. Daher wurden zwei Methoden vorgeschlagen, um den Zugriff auf die Router-Instanz zu ermöglichen.

Die erste ist direkter, bei der ein globales Webpack für die Instanz festgelegt wird.

Die zweite Möglichkeit besteht darin, Promises mit Ihrer vuex-Aktion zu verwenden, mit der Ihre Komponenten ihren Verweis auf die Router-Instanz nach den Aktionen Promise auflösen / ablehnen können.


2
Dies sollte die Antwort speziell für
Vue

6

ERSTE ANTWORT

In main.js(dem, in dem wir alle Module "installieren" und eine VueInstanz erstellen , dh src/main.js):

const vm = new Vue({
  el: '#app',
  router,
  store,
  apolloProvider,
  components: { App },
  template: '<App/>'
})

export { vm }

Dies ist mein Beispiel, aber in unserem Fall ist das wichtigste hier const vmundrouter

In Ihrem store:

import { vm } from '@/main'

yourMutation (state, someRouteName) {
  vm.$router.push({name: someRouteName})
}

PS Mit können import { vm } from '@/main'wir auf alles zugreifen, was wir brauchen Vuex, zum Beispiel vm.$rootwas von einigen Komponenten von benötigt wird bootstrap-vue.

PPS Es scheint, dass wir nur verwenden können, vmwenn alles geladen ist. Mit anderen Worten, wir können vminside nicht verwenden someMutation, falls wir someMutationinside aufrufen mounted(), da mounted()es vor dem Erstellen kommt / auftritt vm.


NEUE ANTWORT

Constantins Antwort (die akzeptierte) ist besser als meine, also möchte ich Anfängern nur zeigen, wie man sie umsetzt.

Innenkern dir (innen /srcin meinem Fall), neben App.vue, main.jsund andere , die ich habe router.jsmit dem Inhalt:

import Vue from 'vue'
import Router from 'vue-router'

// Traditional loading
import Home from '@/components/pages/Home/TheHome'

// Lazy loading (lazy-loaded when the route is visited)
const Page404 = () => import(/* webpackChunkName: "Page404" */ '@/components/pages/404)
const Page503 = () => import(/* webpackChunkName: "Page503" */ '@/components/pages/503)

Vue.use(Router)

const router = new Router({
  mode: 'hash',
  base: process.env.BASE_URL,
  linkExactActiveClass: 'active',
  routes: [
    {
      path: '*',
      name: 'Page404',
      component: Page404
    },

    {
      path: '*',
      name: 'Page503',
      component: Page503
    },

    {
      path: '/',
      name: 'Home',
      component: Home
    },

    // Other routes
    {....},
    {....}
  ]
})

// Global place, if you need do anything before you enter to a new route.
router.beforeEach(async (to, from, next) => {
  next()
})

export default router

Importieren Sie unseren Router nach main.js:

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

const vm = new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

export { vm }

Schließlich innerhalb Ihrer Komponente oder Vuex oder irgendwo anders import router from './router'und tun, was Sie brauchen, wie zrouter.push(...)


5

Ich mochte es nicht, den Standortstatus meiner App vom Rest meines App-Status im Store zu trennen und sowohl einen Router als auch einen Store verwalten zu müssen. Deshalb habe ich ein Vuex-Modul erstellt, das den Standortstatus im Store verwaltet.

Jetzt kann ich wie bei jeder anderen Statusänderung durch Auslösen von Aktionen navigieren:

dispatch("router/push", {path: "/error"})

Dies hat den zusätzlichen Vorteil, dass animierte Seitenübergänge einfacher zu handhaben sind.

Es ist nicht schwer, ein eigenes routerModul zu rollen , aber Sie können auch mein Modul ausprobieren, wenn Sie möchten:

https://github.com/geekytime/vuex-router

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.