Skip to content

路由守卫

守卫会在路由成为当前路由之前执行。守卫不返回值表示放行,返回 false 表示中止,返回字符串或命名 location 表示重定向。所有守卫都可以是异步函数。

鉴权示例

将权限策略写在路由元信息中,再使用一个全局守卫统一执行:

ts
router.beforeEach(async (to) => {
  if (!to.meta.requiresAuth) return;
  if (auth.session.value) return;

  return {
    name: "login",
    query: { redirect: to.fullPath },
  };
});

注册函数会返回移除守卫的回调:

ts
const stopAuthGuard = router.beforeEach(checkSession);
stopAuthGuard();

全局钩子

beforeEach 适合权限策略与重定向。beforeResolve 会在目标懒加载页面组件加载完成之后执行,因此适合准备页面必要的数据。afterEach 可观察成功与失败的尝试,onError 会接收抛出的错误(包括重定向循环)。

ts
router.beforeResolve(async (to) => {
  if (to.name === "dashboard") await dashboardStore.load();
});

router.afterEach((to, from, failure) => {
  if (!failure) analytics.page(to.fullPath, from.fullPath);
});

router.onError((error) => reportError(error));

路由记录守卫

beforeEnter 只属于即将进入的记录。它可以是一个守卫,也可以是数组,适合放置该路由专有的校验。

ts
{
  path: "/admin",
  component: () => import("../pages/admin-page"),
  beforeEnter: [requireSession, requireAdmin]
}

阻止未保存修改丢失

在路由组件 setup 时调用组件守卫组合式函数。元素卸载时,它们会自动注销。

ts
import { onBeforeRouteLeave, onBeforeRouteUpdate, useRoute } from "@elfui/router";

const route = useRoute();

onBeforeRouteLeave(() => {
  return form.isDirty.value ? window.confirm("放弃未保存的修改?") : true;
});

onBeforeRouteUpdate(async (to, from) => {
  if (to.params.id !== from.params.id) {
    await loadUser(String(to.params.id));
  }
});

组件守卫涵盖离开与更新。ElfUI 页面是 Custom Element,因此没有 Vue Options API 风格、接收实例参数的 beforeRouteEnter 回调。

执行顺序

一次普通导航中,守卫按以下顺序执行:

  1. 被停用记录的 leave 守卫,由最深层开始。
  2. 全局 beforeEach 守卫。
  3. 被复用记录的 update 守卫。
  4. 新进入记录的 beforeEnter 守卫。
  5. 加载目标的懒组件。
  6. 全局 beforeResolve 守卫。
  7. 确认导航,然后执行 afterEach

WARNING

返回重定向会开始一次新导航。不要让所有目标都重定向回自身;重定向循环会通过 onError 上报。