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

我们将介绍如何存储上次已知路由,然后在需要时获取它。在本示例中,我们将在 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
变量添加更多条件来进一步扩展它,但这给了我们足够多的信息来理解如何使上次访问的路由保持持久性并在需要时检索它。
很棒的文章!我想知道为什么我们不为此使用 History API?https://mdn.org.cn/en-US/docs/Web/API/History_API
看起来在某些方面它可能更简洁,因为您无需使用 localStorage。不过,我还没有尝试过。谢谢!
不确定我是否同意这段代码的目标,但它仍然是向人们介绍路由钩子的好方法。做得好。