Vue 3源码极客之:`Vue`的`Router`导航守卫:`beforeEach`、`beforeEnter`等的执行顺序。

各位观众老爷,大家好!我是你们的老朋友,今天咱们来聊聊Vue 3里边Router的那些导航守卫,特别是 beforeEachbeforeEnter 这些家伙的执行顺序。这玩意儿啊,看似简单,但真要搞不清楚,就像走迷宫一样,绕来绕去,最后都不知道自己在哪儿了。

今天咱们就来拨开云雾见青天,把这些守卫的执行顺序给它安排得明明白白,让你的代码跑得顺顺溜溜!

开场白:导航守卫,路由界的保安

首先,咱们得明白导航守卫是个啥玩意儿。你可以把它们想象成路由界的保安,每当你想要进入某个页面之前,这些保安都要先盘问一番,看看你有没有通行证,或者有没有什么不良企图,只有通过了它们的检查,你才能顺利进入目标页面。

Vue Router 提供了几种不同的导航守卫,包括:

  • 全局守卫: beforeEachafterEachbeforeResolve
  • 路由独享守卫: beforeEnter
  • 组件内的守卫: beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave

今天咱们重点关注 beforeEachbeforeEnter,因为它们是控制路由跳转的关键环节,也是最容易让人感到困惑的地方。

beforeEach:全局“海关”

beforeEach 是一个全局前置守卫,也就是说,每次路由跳转之前,它都会被执行。你可以把它想象成一个全局的“海关”,所有进出你网站的“旅客”(路由)都要经过它的检查。

import { createRouter, createWebHistory } from 'vue-router';

const routes = [
  { path: '/', component: () => import('./components/Home.vue') },
  { path: '/about', component: () => import('./components/About.vue'), meta: { requiresAuth: true } },
  { path: '/login', component: () => import('./components/Login.vue') }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

router.beforeEach((to, from, next) => {
  console.log('beforeEach: 全局路由守卫被触发');

  // 模拟用户是否登录
  const isLoggedIn = localStorage.getItem('token');

  if (to.meta.requiresAuth && !isLoggedIn) {
    console.log('beforeEach: 用户未登录,重定向到登录页面');
    next('/login');
  } else {
    console.log('beforeEach: 允许访问');
    next();
  }
});

export default router;

在这个例子中,beforeEach 检查每个路由是否需要用户登录 (meta.requiresAuth),如果需要且用户未登录,则会重定向到登录页面。

beforeEnter:路由独享的“门卫”

beforeEnter 是一个路由独享的守卫,也就是说,它只会在进入特定的路由时被执行。你可以把它想象成某个页面的“门卫”,只有你想进入这个页面的时候,它才会出来盘问你。

import { createRouter, createWebHistory } from 'vue-router';

const routes = [
  { path: '/', component: () => import('./components/Home.vue') },
  {
    path: '/profile',
    component: () => import('./components/Profile.vue'),
    beforeEnter: (to, from, next) => {
      console.log('beforeEnter: Profile页面的路由独享守卫被触发');

      // 模拟检查用户权限
      const hasPermission = true;

      if (hasPermission) {
        console.log('beforeEnter: 用户有权限访问Profile页面');
        next();
      } else {
        console.log('beforeEnter: 用户没有权限访问Profile页面,重定向到首页');
        next('/');
      }
    }
  },
  { path: '/login', component: () => import('./components/Login.vue') }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

router.beforeEach((to, from, next) => {
    console.log('beforeEach: 全局路由守卫被触发');
    next();
});

export default router;

在这个例子中,beforeEnter 只会在进入 /profile 路由时被执行,它会检查用户是否有权限访问该页面。

执行顺序:谁先谁后,井然有序

重点来了!beforeEachbeforeEnter 的执行顺序是怎样的呢?答案是:

  1. beforeEach (全局前置守卫):最先执行,所有路由跳转都会触发它。
  2. beforeEnter (路由独享守卫):只有在进入特定路由时才会执行,且在 beforeEach 之后执行。

为了更好地理解,咱们用一个表格来总结一下:

守卫类型 执行时机 作用范围 执行顺序
beforeEach 每次路由跳转之前 全局 1
beforeEnter 进入特定路由之前 特定路由 2

实战演练:代码演示与分析

为了更直观地看到执行顺序,咱们来写一段代码,并在控制台输出一些信息:

// App.vue
<template>
  <div>
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link> |
    <router-link to="/profile">Profile</router-link> |
    <router-link to="/login">Login</router-link>
    <router-view />
  </div>
</template>

<script>
import { defineComponent } from 'vue';

export default defineComponent({
  name: 'App'
});
</script>
// components/Home.vue
<template>
  <h1>Home Page</h1>
</template>
// components/About.vue
<template>
  <h1>About Page</h1>
</template>
// components/Profile.vue
<template>
  <h1>Profile Page</h1>
</template>
// components/Login.vue
<template>
  <h1>Login Page</h1>
</template>

然后,在 router/index.js 中添加以下代码:

import { createRouter, createWebHistory } from 'vue-router';

const routes = [
  { path: '/', component: () => import('../components/Home.vue') },
  { path: '/about', component: () => import('../components/About.vue'), meta: { requiresAuth: true } },
  {
    path: '/profile',
    component: () => import('../components/Profile.vue'),
    beforeEnter: (to, from, next) => {
      console.log('beforeEnter: Profile页面的路由独享守卫被触发');
      next();
    }
  },
  { path: '/login', component: () => import('../components/Login.vue') }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

router.beforeEach((to, from, next) => {
  console.log('beforeEach: 全局路由守卫被触发');
  next();
});

export default router;

现在,启动你的 Vue 应用,并在浏览器中切换路由,观察控制台的输出。你会发现,每次路由跳转,beforeEach 都会被首先执行,而只有当你点击 /profile 链接时,beforeEnter 才会执行,且在 beforeEach 之后。

深入理解:next() 函数的重要性

在导航守卫中,next() 函数至关重要。它决定了路由是否可以继续跳转。

  • next() 允许路由继续跳转到目标页面。
  • next(false) 中断当前的路由跳转。
  • next('/path') 重定向到指定的路径。
  • next(error) 中断导航,并将错误传递给 router.onError() 注册的回调。

如果你忘记调用 next() 函数,或者错误地调用了 next(false),你的路由可能就无法正常跳转了。

应用场景:灵活运用,解决实际问题

了解了 beforeEachbeforeEnter 的执行顺序,你就可以灵活运用它们来解决实际问题了。

  • 权限控制: 使用 beforeEach 检查用户是否已登录,如果未登录,则重定向到登录页面。
  • 页面访问统计: 使用 beforeEach 记录用户的访问行为,例如访问时间、来源页面等。
  • 动态路由配置: 使用 beforeEnter 根据用户的角色动态加载不同的组件。

注意事项:避免踩坑,确保代码健壮

在使用导航守卫时,还需要注意以下几点:

  • 避免死循环:beforeEach 中重定向到当前路由,可能会导致死循环。
  • 异步操作:beforeEach 中进行异步操作时,务必确保在操作完成后再调用 next() 函数。
  • 参数传递: 可以通过 to.paramsto.query 获取路由参数。
  • 使用 meta 字段: 可以在路由配置中使用 meta 字段来存储一些自定义的信息,例如是否需要登录、页面标题等。

总结:掌握核心,游刃有余

今天咱们深入探讨了 Vue Router 中 beforeEachbeforeEnter 的执行顺序。希望通过今天的讲解,你能够对它们有更深刻的理解,并在实际项目中灵活运用,写出更加健壮、高效的代码。

记住,beforeEach 是全局的“海关”,beforeEnter 是路由独享的“门卫”,掌握它们的执行顺序,就能更好地控制你的路由跳转,让你的应用更加安全、可靠。

最后,希望大家在学习 Vue 的道路上越走越远,早日成为一名真正的 Vue 大师!

感谢大家的观看,咱们下期再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注