前端夯实篇:路由守卫

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

路由守卫是什么

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

路由守卫的几种类型

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()函数,防止死循环。

结语

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

相关推荐
你挚爱的强哥2 小时前
✅✅✅【Vue.js】sd.js基于jQuery Ajax最新原生完整版for凯哥API版本
javascript·vue.js·jquery
y先森3 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy3 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189113 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿4 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡5 小时前
commitlint校验git提交信息
前端
天天进步20155 小时前
Vue+Springboot用Websocket实现协同编辑
vue.js·spring boot·websocket
虾球xz5 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇5 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒5 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript