Vue Router:保留查询参数并为子级使用相同的视图

Vue Router: Keep query parameter and use same view for children

我正在用 Vue 重写现有的 Angular 1 个应用程序。

应用程序 总是 需要在进入任何视图之前通过 localeidtoken 对用户进行身份验证。尊重我们 API 的约定,我将 token 指定为我的主要父路由中的查询参数。

来自现有的 Angular 的 UI 路由器实现,我认为这是要走的路:

// main.js
new Vue({
  el: '#app',
  router,
  store,
  template: '<router-view name="main"></router-view>'
})

// router.js
const router = new Router({
  mode: 'history',
  routes: [
    {
      name: 'start',
      path : '/:locale/:id', // /:locale/:id?token didn't work
      query: {
        token: null
      },
      beforeEnter (to, from, next) {
        // 1. Get data from API via locale, id and token
        // 2. Update store with user data
      },
      components: {
        main: startComponent
      },
      children: [{
        name: 'profile',
        path: 'profile',
        components: {
          main: profileComponent
        }
      }]
    }
  ]
})    

当我导航到 profile 视图时,我希望视图发生变化并且查询令牌保持不变,例如/en-US/123?token=abc/en-US/123/profile?token=abc。两者都没有。

我正在使用 Vue 2.3.3 和 Vue Router 2.3.1。

问题:

你可以在路由器的全局钩子中解决这个问题

import VueRouter from 'vue-router';
import routes from './routes';

const Router = new VueRouter({
  mode: 'history',
  routes
});

function hasQueryParams(route) {
  return !!Object.keys(route.query).length
}

Router.beforeEach((to, from, next) => {
   if(!hasQueryParams(to) && hasQueryParams(from)){
    next({name: to.name, query: from.query});
  } else {
    next()
  }
})

如果新路由(to)没有自己的参数,那么它们将取自之前的路由(from)

你可以添加一个 mounted 挂钩路由器导航守卫 beforeEach 像这样 preserveQueryParams:

// helpers.js
import isEmpty from 'lodash/isEmpty';

const preserveQueryParams = (to, from, next) => {
  const usePreviousQueryParams = isEmpty(to.query) && !isEmpty(from.query);
  if (usePreviousQueryParams) {
    next({ ...to, query: from.query });
  } else {
    next();
  }
};
// StartComponent.vue
removeBeforeEachRouteGuard: Function;

mounted() {
  this.removeBeforeEachRouteGuard = this.$router.beforeEach(preserveQueryParams);
}

// don't forget to remove created guard
destroyed() {
  this.removeBeforeEachRouteGuard();
  // resetting query can be useful too
  this.$router.push({ query: {} });
}