在 Vue 中存储和使用上次已知路由

Avatar of Mateusz Rybczonek
Mateusz Rybczonek

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费积分!

在某些情况下,保留用户访问的最后一个路由的引用会很方便。例如,假设我们正在使用一个多步骤表单,用户从一个步骤继续到下一步。如果用户离开并稍后返回来完成表单,最好保留该前一个步骤的路由,以便我们知道用户停止的位置。

我们将介绍如何存储上次已知路由,然后在需要时获取它。在本示例中,我们将在 Vue 中工作,并使用 vue-router 进行路由,并使用 localStorage 来保存上次访问路由的信息。

以下是我们将要处理的示例

首先,让我们概述路由结构

我们的示例共有三个路由

  • /home
  • /hello
  • /goodbye

每个路由都需要分配一个 name 属性,因此让我们将其添加到我们的 router.js 文件中

// router.js

import Vue from "vue";
import Router from "vue-router";
import Hello from "@/components/Hello";
import Goodbye from "@/components/Goodbye";

import {
  HELLO_URL,
  GOODBYE_URL
} from "@/consts";

Vue.use(Router);

const router = new Router({
  mode: "history",
  routes: [
    { path: "/", name: "home" },
    { path: HELLO_URL, name: "hello", component: Hello },
    { path: GOODBYE_URL, name: "goodbye", component: Goodbye }
  ]
});

export default router;

接下来,让我们回顾一下需求

我们知道第一个需求是在 localStorage 中存储上次访问的路由。其次,我们需要能够检索它。但是,应该在什么条件下获取和应用路由呢?这给了我们两个额外的需求。

  • 用户进入主路由 (/home),然后离开该路由,然后想要返回该路由。
  • 用户处于非活动状态一段时间,会话过期,我们希望在重新启动会话后将用户返回到他们上次所在的屏幕。

为了继续进行重定向,我们需要满足这四个需求。

现在让我们进入代码。

需求 1:在 localStorage 中保存最后一个路由名称

我们希望将上次访问的路由的引用保存在 localStorage 中。例如,如果用户在 /checkout 中然后离开网站,我们希望保存该信息,以便以后完成购买。

为此,我们希望在用户进入任何新路由时保存路由名称。我们将使用一个称为 导航守卫afterEach,它在每次路由转换完成后被触发。它提供一个 to 对象,该对象是目标 路由对象。在该钩子中,我们可以提取该路由的名称,并使用 setItem 方法将其保存到 localStorage 中。

// router.js

const router = new Router( ... );

router.afterEach(to => {
  localStorage.setItem(LS_ROUTE_KEY, to.name);
});

...
export default router;

需求 2:从 localStorage 获取最后一个路由名称并重定向

现在已保存最后一个路由的名称,我们需要能够获取它并在需要时触发重定向。我们希望在进入新路由之前检查是否应该重定向,因此我们将使用另一个名为 beforeEach 的导航守卫。该守卫接收三个参数

  • to:目标路由对象
  • from:当前导航到的路由
  • next:必须在守卫中调用的函数以解决钩子

在该守卫中,我们使用 localStorage.getItem() 方法读取上次访问的路由的名称。然后,我们确定是否应该重定向用户。此时,我们检查目标路由 (to) 是否是我们的主路由 (/home),以及我们是否确实在 localStorage 中拥有最后一个路由。

如果满足这些条件,我们将触发包含上次访问的路由名称的 next 方法。这将依次触发到该路由的重定向。

如果任何条件失败,我们将触发 next 而不带任何参数。这将使用户转到管道中的下一个钩子,并继续进行普通路由而无需重定向。

// router.js

const router = new Router( ... );

router.beforeEach((to, from, next) => {
  const lastRouteName = localStorage.getItem(LS_ROUTE_KEY);
  
  const shouldRedirect = Boolean(
    to.name === "home" &&
    lastRouteName 
  );

  if (shouldRedirect) next({ name: lastRouteName });
  else next();
});

...
export default router;

这涵盖了四个需求中的两个!让我们继续进行第三个需求。

需求 3:首次访问条件

现在,我们需要检查用户是首次访问主路由(来自不同来源),还是从应用程序中的其他路由导航到该路由。我们可以通过添加一个标志来实现这一点,该标志在创建路由器时设置为 true,并在第一次转换完成后设置为 false。

// router.js

const router = new Router( ... );

let isFirstTransition = true;

router.beforeEach((to, from, next) => {
  const lastRouteName = localStorage.getItem(LS_ROUTE_KEY);
  
  const shouldRedirect = Boolean(
    to.name === "home" &&
    && lastRouteName
    && isFirstTransition
  );

  if (shouldRedirect) next({ name: lastRouteName });
  else next();

  isFirstTransition = false;
});

...
export default router;

好的,我们还需要满足一个需求:如果用户处于非活动状态的时间超过特定时间段,我们希望将用户重定向到最后一个已知路由。

需求 4:活动时间条件

同样,我们将使用 localStorage 来保存有关用户上次访问的路由的信息。

beforeEach 守卫中,我们将从 localStorage 获取路由并检查从那时起经过的时间是否在我们的阈值内(由 hasBeenActiveRecently 定义)。然后,在我们的 shouldRedirect 中,我们将确定是否应该进行路由重定向。

我们还需要保存该信息,这将在 afterEach 守卫中完成。

// router.js

const router = new Router( ... );

let isFirstTransition = true;

router.beforeEach((to, from, next) => {  
  const lastRouteName = localStorage.getItem(LS_ROUTE_KEY);
  const lastActivityAt = localStorage.getItem(LS_LAST_ACTIVITY_AT_KEY);

  const hasBeenActiveRecently = Boolean(
    lastActivityAt && Date.now() - Number(lastActivityAt) < MAX_TIME_TO_RETURN
  );

  const shouldRedirect = Boolean(
    to.name === "home" &&
    && lastRouteName
    && isFirstTransition
    && hasBeenActiveRecently
  );

  if (shouldRedirect) next({ name: lastRouteName });
  else next();

  isFirstTransition = false;
});

router.afterEach(to => {
  localStorage.setItem(LS_ROUTE_KEY, to.name);
  localStorage.setItem(LS_LAST_ACTIVITY_AT_KEY, Date.now());
});

...
export default router;

我们满足了需求!

就是这样!我们涵盖了所有四个需求,即

  • 我们将在 localStorage 中存储上次访问的路由
  • 我们有一个方法可以从 localStorage 中检索上次访问的路由
  • 如果用户是首次访问应用程序,我们将将其重定向回主路由
  • 在一定时间段内,我们将向用户提供重定向到最后一个已知路由的功能

当然,我们可以通过为应用程序添加更多复杂性和为 shouldRedirect 变量添加更多条件来进一步扩展它,但这给了我们足够多的信息来理解如何使上次访问的路由保持持久性并在需要时检索它。