导航到同一路由后,beforeEnter 添加的 Vue Router 路由查询参数丢失

Vue Router route query param added by beforeEnter lost after navigate into the same route

当导航到您当前所在的同一路线时,在进入路线守卫之前添加的路线查询page丢失。

这是由于路由器 link to 对象不包含查询 page,并且它在进入 hook[= 之前​​不进入 51=] 了,因为它已经在同一条路线上了。

我发现您可以将它添加到您的路由器推送或 link 按钮中,并且只要您知道视图包含查询 page.

就需要添加它

示例:

this.$router.push({ name: 'routeName', query: { page: 1 } });

问题:

有没有一种优雅的方法可以在路由守卫中处理这个问题?

我应该使用哪个挂钩,以便即使用户导航到同一路线也可以保留路线查询 page

示例代码:

路线

// Sample route
const routes =  [
  {
    path: 'test',
    name: 'Test',
    component: TestPage,
    beforeEnter: testPageGuard,
  },
];

路由守卫

// Test Page Guard
testPageGuard: (to, from, next) => {
  const { page = null } = to.query;  
  let finalNext;

  if (!page) {
    finalNext = {
      ...to,
      query: {
        ...to.query,
        page: 1,
      },
    };
  }

  if (finalNext) {
    next(finalNext);
  } else {
    next();
  }
}

查看

// TestPage.vue
<template>
  <!-- The problem can be reproduce when clicking this link 
       when you are already in route '/test'               -->
  <router-link :to="{ name: 'Test'}">
    Test
  </router-link>
</template>

<script>
export default {
  name: 'Test',
};
</script>

解决方案:

  • 将查询 页面 添加到路由器 link
// TestPage.vue
<template>
  <!-- query page is added here -->
  <router-link :to="{ name: 'Test', query: { page: 1 } }">
    Test
  </router-link>
</template>

<script>...</script>

我发现还有两种方法可以做到这一点。

解决方案一:在“beforeRouteUpdate”挂钩处更新

beforeRouteUpdate 在查询参数更改时触发,即使在同一路由中也是如此。

因此我们可以删除 beforeEnter 守卫和路由 link 中额外的 page 查询,并添加查询参数 page在该特定页面。

示例代码

查看

// TestPage.vue
<template>
  <!-- The problem can be reproduce when clicking this link 
       when you are already in route '/test'               -->
  <router-link :to="{ name: 'Test'}">
    Test
  </router-link>
</template>

<script>
export default {
  name: 'Test',

  // Solution here
  beforeRouteUpdate(to, from, next) {
    if (!Object.prototype.hasOwnProperty.call(to.query, 'page')) {
      next({
        ...to,
        query: {
          // This line is used to retain other query if there is any
          ...to.query,
          page: 1,
        },
      });
    } else {
      next();
    }
  },
};
</script>

解决方案 2:在“beforeEach”挂钩处更新

即使在同一路由中查询参数发生变化,它实际上也会通​​过 beforeEach 挂钩。

因此我们可以删除 beforeEnter 守卫和路由 link.

中额外的 page 查询

为该路由添加元标记 hasQueryParamPage 并在全局 beforeEach 挂钩中添加查询参数 page

如果您有其他页面需要查询参数 page.

,此设计具有更好的可重用性

示例代码

路线

// Sample route
const routes =  [
  {
    path: 'test',
    name: 'Test',
    component: TestPage,
    // add meta tag
    meta: { hasQueryParamPage: true },
  },
];

路由器

// router.js
const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
...
});

// Solution here
router.beforeEach((to, from, next) => {
  if (to.matched.some((record) => (record.meta.hasQueryParamPage))) {
    let updatedNext = null;

    if (!Object.prototype.hasOwnProperty.call(to.query, 'page')) {
      updatedNext = {
        ...to,
        query: {
          // This line is used to retain other query if there is any
          ...to.query,
          page: 1,
        },
      };
    }
    
    if (updatedNext) {
      next(updatedNext);
      return;
    }
  }

  next();
});