前端夯实篇:路由守卫

路由守卫?这是个什么东西,听着如此高级。

路由守卫是什么

许多网站的详情页需要我们登录了才可以访问,这就是路由守卫。顾名思义,将没有登录授权的我们守在外面不让进,想进去得先登录账号。这样的功能是不是很常见,当然并不仅仅有这一种情况,很多场景都需要路由守卫,所以了解并掌握它对于学习前端的我们是非常重要的。

路由守卫的几种类型

1. 全局守卫 :在任何路由跳转前或后执行,如beforeEachafterEach

2. 独享守卫 :只在某个特定路由的进入和离开时执行,如beforeEnter

3. 组件内的守卫 :在组件级别的导航守卫,如beforeRouteEnterbeforeRouteUpdate

现在我们来一一介绍:

全局守卫:

beforeEach(全局前置守卫)是最常用的路由守卫类型,就是来满足未登录就访问不了的情况,它会带上三个参数,分别是:to 、 from 、 next ,想必大家看到这几个单词就大概猜出它们分别的作用了,说再多都不如上个例子:

js 复制代码
// 全局的路由守卫
const whitePath = ['/login', '/register', '/noteClass']
router.beforeEach((to, from, next) => {
  if (!whitePath.includes(to.path)) {  // 需要校验登录权限
    // 判断浏览器本地有无userInfo
    if (!localStorage.getItem('userInfo')) {  // 没登录
      router.push('/login')
      return
    }
    next()
    return
  }
  next()
})

当每次路由发生变化时,这个函数都将执行,其中三个参数的含义是:

  • to: 将去向的路由

  • from: 当前的路由

  • next: 放行,允许到达 to 这个路由,也就是即将去的路由

这下是不是豁然开朗了,这段代码在最开始定义了一个白名单,其中包含 login(登录页面)、register(注册页面)、noteClass(主页),不难看出,这三个页面都是我们不需要登录就可以访问的。

下一步则开始设计我们的路由守卫函数:首先,判断 to 的 path (即将去往的路由)是否在白名单中,如果不在,直接走到第13行的 next() 放行,反之继续判断用户是否已经登录,通过判断 localStorage 中是否有用户的登录信息来检测用户是否登录,倘若有值,则直接走到第10行的 next() 放行,反之走 if 中的 router.push('/login')语句,即跳到登录页。这场景是不是非常熟悉,当然,大部分场景是弹出一个登录框,与之相似。

localStorage:浏览器的小数据库,当用户登录时会将登录信息以key value的形式存在里面。

独享守卫

与全局守卫的写法一模一样,只不过放的位置不一样。独享守卫,顾名思义,由一个路由独享,所以它是写在路由里面的。就像这样:

js 复制代码
const routes = [
  { path: '/', component: Home },
  {
    path: '/profile',
    component: Profile,
    beforeEnter: (to, from, next) => {
      // 假设我们有一个 isUserLoggedIn 方法来检查用户是否登录
      const isLoggedIn = isUserLoggedIn();

      if (isLoggedIn) {
        // 如果用户已登录,允许访问
        next();
      } else {
        // 如果未登录,重定向到登录页面
        next('/login');
      }
    }
  },
  { path: '/login', component: Login }
];

直接写在路由里面,由该路由独享这个守卫

组件内的守卫

beforeRouteEnterbeforeRouteUpdate 是提供给组件的守卫,直接写在组件中,它们分别在不同的时机触发,用于在导航过程中执行特定的操作。

举例:

假设我们有一个用户详情页面,页面上需要显示用户的个人信息,这些信息需要从服务器动态加载。同时,当用户在页面上修改某些信息并保存后,我们希望再次访问该页面时能够看到最新的信息,而不是缓存中的旧数据。

beforeRouteEnter

beforeRouteEnter 守卫在组件被创建之前被调用,也就是说在组件实例化之前,你就可以开始加载数据。这在数据加载完之后才渲染组件的情况下非常有用,因为这样可以避免组件先渲染出空白界面,然后数据加载完成后才填充内容。

js 复制代码
// UserDetail.vue
<template>
    <div>
        <h1>User Detail</h1>
        <p>Name: {{ user.name }}</p>
        <p>Email: {{ user.email }}</p>
    </div>
</template>

<script>
import axios from 'axios';

export default {
    data() {
        return {
            user: {}
        };
    },
    beforeRouteEnter(to, from, next) {
        axios.get(`/api/users/${to.params.userId}`)
            .then(response => {
                // 由于 beforeRouteEnter 守卫无法访问 this,所以需要使用 next 回调函数传递结果
                next(vm => {
                    vm.user = response.data;
                });
            });
    }
};
</script>

beforeRouteUpdate

beforeRouteUpdate 则是在组件实例已经创建并且渲染过之后,但在路由参数或查询变化导致的重新渲染之前被调用。这使得你可以在参数变化时执行一些额外的逻辑,例如重新加载数据。

js 复制代码
// UserDetail.vue
<template>
    <!-- 同上 -->
</template>

<script>
import axios from 'axios';

export default {
    data() {
        return {
            user: {}
        };
    },
    beforeRouteEnter(to, from, next) {
        // 同上
    },
    beforeRouteUpdate(to, from, next) {
        if (to.params.userId !== from.params.userId) {
            // 如果用户 ID 发生变化,重新加载数据
            axios.get(`/api/users/${to.params.userId}`)
                .then(response => {
                    this.user = response.data;
                    next(); // 重要!必须调用 next() 来完成导航
                })
                .catch(error => {
                    console.error('Failed to fetch user:', error);
                    next(); // 即使出现错误,也要调用 next() 来完成导航
                });
        } else {
            next();
        }
    }
};
</script>

在这个例子中,beforeRouteEnter 负责在首次进入页面时加载用户数据,而 beforeRouteUpdate 则确保当用户 ID 参数发生变化时,数据能够被重新加载。这样,无论何时用户通过导航重新访问该页面,都能看到最新的数据。

需要注意的地方

  1. 保持守卫逻辑简洁 - 避免在守卫中编写过于复杂的业务逻辑,以防影响性能。
  2. 使用async/await - 当你需要异步操作时,使用async/await可以让守卫的代码更清晰易读。
  3. 避免无限循环 - 确保在守卫中正确调用next()函数,防止死循环。

结语

你如果不想用户还没登录就进入"我的主页"的话,记得用路由守卫。

相关推荐
多多*34 分钟前
Spring之Bean的初始化 Bean的生命周期 全站式解析
java·开发语言·前端·数据库·后端·spring·servlet
linweidong39 分钟前
在企业级应用中,你如何构建一个全面的前端测试策略,包括单元测试、集成测试、端到端测试
前端·selenium·单元测试·集成测试·前端面试·mocha·前端面经
满怀10151 小时前
【HTML 全栈进阶】从语义化到现代 Web 开发实战
前端·html
东锋1.31 小时前
前端动画库 Anime.js 的V4 版本,兼容 Vue、React
前端·javascript·vue.js
满怀10151 小时前
【Flask全栈开发指南】从零构建企业级Web应用
前端·python·flask·后端开发·全栈开发
小杨升级打怪中2 小时前
前端面经-webpack篇--定义、配置、构建流程、 Loader、Tree Shaking、懒加载与预加载、代码分割、 Plugin 机制
前端·webpack·node.js
Yvonne爱编码2 小时前
CSS- 4.4 固定定位(fixed)& 咖啡售卖官网实例
前端·css·html·状态模式·hbuilder
SuperherRo2 小时前
Web开发-JavaEE应用&SpringBoot栈&SnakeYaml反序列化链&JAR&WAR&构建打包
前端·java-ee·jar·反序列化·war·snakeyaml
大帅不是我3 小时前
Python多进程编程执行任务
java·前端·python
前端怎么个事3 小时前
框架的源码理解——V3中的ref和reactive
前端·javascript·vue.js