如何使用Vuex动作中的Vue路由器导航


76

我正在使用Vue 2.x和Vuex 2.x创建一个Web应用程序。我正在通过http调用从远程位置获取一些信息,我希望如果该调用失败,我应该重定向到其他页面。

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

但是this.$router.push({path:"/"})给我以下错误。

未捕获(承诺)TypeError:无法读取未定义的属性“ push”

如何做到这一点。

模拟的JsFiddle:在这里


这是因为您正在将箭头“ this”视为文字的箭头函数中使用它。将其转换为常规函数或使用以下建议的答案...
EldadT

Answers:



15

本示例可能会为您提供帮助。

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},

    ]
})

actions.js

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

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

    router.push("/welcome");
} 

这不是应该使用Vue的方式。动作不应该有副作用。用组件的方法来解决此问题,例如dispatch('someAction').then(() => this.$router.push('/welcome'))
adriaan

2
@adriaan并不完全正确,即使vuex演示中的动作也有副作用。
Blowsie

11

看来您没有将路由器注入应用程序,因此它是“未定义的”

在早期版本的vue-router中,您将:Vue.use(VueRouter)使用2.0将路由器注入到应用中,如下所示:

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

const router = new VueRouter({
  routes
})

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

然后应该使它this.$router在整个应用程序中都可用


在回答了一个相关的问题之后:如何从Vuex状态使用Vue路由器?看来Vuex不会在接收路由器实例this.$router。因此,建议使用两种方法来提供对路由器实例的访问。

第一个是更直接的,它涉及将Webpack全局设置为实例。

第二个涉及将Promises与vuex动作一起使用,这将允许您的组件在Promise解决/拒绝动作之后使用它们对路由器实例的引用。


2
这应该是专门针对vue 2的答案
编码为

6

初始答案

main.js(其中一个我们“安装”所有模块并创建Vue实例的位置,即src/main.js)中:

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

export { vm }

这是我的例子,但在我们的例子在这里最重要的是const vmrouter

在您的store

import { vm } from '@/main'

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

PS使用import { vm } from '@/main'我们可以访问我们需要的任何东西Vuex,例如vm.$root某些组件所需的bootstrap-vue

PPS似乎我们可以vm在加载所有内容时使用。换句话说,我们不能用vm里面someMutation的情况下,如果我们称之为someMutationmounted(),因为mounted()自带/发生之前vm被创建。


新答案

康斯坦丁的答案(公认的答案)比我的要好,因此只想向新手展示如何实现它。

在核心目录中(/src在我的情况下),在旁边App.vuemain.js以及其他我所router.js拥有的内容:

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

将我们的路由器导入到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 }

最后,在组件内部,Vuex或其他任何地方import router from './router',执行所需的任何操作,例如router.push(...)


5

我不喜欢保持从商店我的应用程序状态的其余部分分开我的应用程序的位置状态,并具有同时管理一个路由器和一个商店,所以我创建了一个管理位置状态的Vuex模块的商店。

现在,我可以像其他状态更改一样通过调度动作进行导航:

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

这具有使动画页面过渡之类的内容更易于处理的附加好处。

滚动自己的router模块并不难,但是如果您愿意,也可以尝试使用我的模块:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.