目录

🔽 概述

1. 全局守卫——全局钩子函数

1.1 全局前置守卫——beforeEach

1.2 全局后置路由守卫

1.3 整合

2. 路由独享的守卫——路由独享的钩子函数

3.组件内的守卫——组件内的钩子函数

🔽 参考资料


Vue-Router导航(路由)守卫就是路由跳转前、中、后过程中的一些钩子函数,本文详细的介绍了Vue中路由守卫的具体使用——vue-router钩子函数实现路由守卫,具有一定的参考价值,对vue感兴趣的同学可以参考一下。

🔽 概述

何为路由守卫?路由守卫有点类似于ajax的请求拦截器,就是请求发送之前先给你拦截住做一些事情之后再去发送请求,同样这里的路由守卫意思差不多;简单理解为就是你在进路由之前,首先把你拦住,对你进行检查;这是不是有点中学门口的保安?进来之前拦住,有学生证就进,没有学生证就不让进;当然,路由守卫不仅仅只是在你进入之前拦住你,还有其他的钩子函数进行其他操作。

闲话:有的时候,需要通过路由来进行一些操作,比如,最常见的登录权限验证,当用户满足条件时,才让其进入导航,否则就取消跳转,并跳到登录页面让其登录。 为此有很多种方法可以植入路由的导航过程:全局的,单个路由独享的,或者组件级的。

路由守卫的作用:对路由进行权限控制

路由守卫的分类:全局守卫、独享守卫、组件内守卫

vue-router一共给我们提供了三大类钩子函数来实现路由守卫:

1、全局钩子函数(beforeEach、afterEach)  ——全局路由钩子

2、路由独享的钩子函数(beforeEnter) ——路由独享守卫

3、组件内钩子函数(beforeRouterEnter、beforeRouterUpdate、beforeRouterLeave)——组件内的守卫

首先我们先来看一下全局钩子函数:

1. 全局守卫——全局钩子函数

全局守卫,也称全局钩子函数、全局路由钩子

1.1 全局前置守卫——beforeEach

顾名思义,前置守卫主要是在你进行路由跳转之前根据你的状态去 进行一系列操作(全局前置是为在路由初始化以及跳转之前都会触发)

你可以使用router.beforeEach注册一个全局前置守卫(Each:每个,即在任意一个路由跳转的时候都会触发)

每个守卫方法接收三个参数:

to:Route:即将进入目标的路由对象

from:Route:当前导航正要离开的路由对象

next:function:一定要调用该方法来resolve这个钩子。执行效果依赖next方法的调用参数

(1). next():进行管道中的下一个钩子(to),即进入该路由。如果钩子执行完了,则导航状态就是confirmed(确认的)

(2). next(false):中断当前的导航,取消进入路由。如果浏览器的URL改变了(可能用户手动或者浏览器按后退按钮),那么地址会重置到from路由对应的地址。

(3). next('/")或者next( { path: '/' } ):跳转到一个新的地址。当前的导航被中断,然后进行下一个新的导航。你可以想next传递任意对象,且允许设置诸如replace:true、name:'home‘ 之类的选项以及任何用下router-link的 to prop或者router.push中的选项

确保next函数在任何给定的导航守卫中被严格调用一次,它可以出现多余一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或者错误。

1.1.1 使用

可以打印出from、to、next看他们究竟会保存那些信息

举例

import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";
import About from "../views/About.vue";
import News from "../views/News.vue";
import Message from "../views/Message.vue";

Vue.use(VueRouter);

const routes = [
  {
    path: "/home",
    name: "Home",
    component: Home,
    children: [
      {
        path: "message", //此处不要写成:/message
        component: Message,
      },
    ],
  },

  {
    path: "/about",
    name: "aboutName",
    component: About,
    children: [
      {
        //通过children配置子级路由
        path: "news", //此处不要写成:/news
        component: News,
      },
    ],
  },
];

const router = new VueRouter({
  routes,
});

//全局前置路由守卫---初始化的时候被调用、每次路由切换的时候被调用
router.beforeEach((to, from, next) => {
  console.log(to); //这里是一个简单的例子 //即判断用户是否进入了需要鉴权的路由下(这里举例为news和message)
  if (to.path == "/home/message" || to.path === "/about/news") {
    //如果进入了,那就判断本地是否缓存了信息(这里模拟登录的token)
    if (localStorage.getItem("name") === "kaodigua") {
      next();
    }
  } else {
    //如果不是,则直接放行即可
    next();
  }
});

export default router;

上面这个例子有个不足之处是,当需要鉴权的路由很多的时候,那你需要一个一个的去判断?那大可不必,因此这里引入路由的另一属性,即meta,可以在每个路由中进行配置,一般用来标识具有标识性的属性,可以用来统一判断,具体如下:

Vue.use(VueRouter);

// 路由字典
const routes = [
  {
    path: "/home",
    name: "Home",
    children: [
      // 通过children配置子级路由
      {
        path: "message", //此处不要写成: /news
        component: MessageChannel,
        meta: {
          isAuth: true, //用于判断是否需要鉴权
        },
      },
    ],
  },
  {
    path: "/about",
    name: "/aboutName",
    component: About,
    children: [
      // 通过children配置子级路由
      {
        path: "news", // 此处不要写成:/news
        component: News,
        meta: {
          isAuth: false, // 表示不需要鉴权
        },
      },
    ],
  },
];

// 路由器对象
const router = new VueRouter({ routes });

//使用meta
router.beforeEach((to, from, next) => {
  console.log(to);
  if (to.meta.isAuth) { //判断是否需要鉴权
   //如果进入了,那就判断本地是否缓存了信息(这里模拟登录的token)
    if (localStorage.getItem("name") === "kaodigua") {
      next();
    }
  } else {
    // 如果不是,直接放行即可
    next();
  }
});

关于全局前置守卫——beforeEach

beforeEach一共接收三个参数,分别是to、from、next;to:即将进入的路由对象;from:正要离开的路由对象;next:路由的控制参数;

next一共有四种调用方式:

👉 next():一切正常调用这个方法进入下一个钩子;

👉 next(false):取消路由导航,这时的url显示的是正要离开的路由地址;

👉 next('/login'):当前路由被终止,进入一个新的路由导航(路由地址可以自由指定)

👉 next(error):路由导航终止并且错误会被传递到router.onError()注册过的回调中;

我们一般是用全局钩子来控制权限,像什么进页面没有登录就跳登录页,需要用户达到什么级别才能访问当前页面都是属于页面权限控制,都是可以通过beforeEach钩子函数来实现:

main.js(全局钩子函数我们一般是在main.js中进行书写):
 

// 进入路由前方法勾子
router.beforeEach((to, from, next) => {
  console.log(to, '前置第一个参数')
  console.log(from, '前置第二个参数')
  console.log(next, '前置第三个参数')
  /*
    to 目标路由
    from 源路由
    next 跳转到下一个路由
  */
//这里暂时用local、storange来简单模拟验证权限
  if (window.localstorange.getItem("token")) {
    // 如果存在,则直接跳转到对应路由
     next();
  } else {
    // 如果不存在,则跳转到登录页
    next('/login');
  }
});

1.2 全局后置路由守卫

//全局后置路由守卫---初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to, from) => {
  if (to.meta.title) {
    document.title = to.meta.title || '路由跳转举例'//修改网页的title
  }else{
    document.title = 'vue_test'
  }
})

关于全局后置守卫——afterEach

AfterEach和beforeEach一样都是属于全局守卫钩子,都是在main.js中进行调用;其中AfterEach比beforeEach少一个next参数;

to:即将进入的路由对象;
from:正要离开的路由对象;

afterEach()我们一般用来重置页面滚动条位置:假如我们有一个页面很长,滚动后其中的某个位置后跳转,这时新的页面的滚动条位置就会在上一个页面停留的位置;这个时候我们就可以利用afterEach进行重置:

//全局路由改变后的钩子
router.afterEach((to, from) => {
  //将滚动条恢复到最顶端
  window.scrollTo(0, 0);
})

1.3 整合

全局守卫

// 全局前置守卫---初始化时执行、每次路由切换前执行
router.beforeEach((to, from, next) => {
  console.log('beforeEach',to,from);
  if (to.meta.isAuth) {//判断当前路由是否需要进行权限控制
    //如果进入了,那就判断本地是否缓存了信息(这里模拟登录的token)
    if (localStorage.getItem("school") === "atguigu") {// 权限控制的具体规则
      next(); // 放行
    }else{
      alert('您暂无权限查看')
      // next({name:'guangyu'})
    }
  } else {
    next(); // 放行
  }
});
​
//全局后置守卫---初始化时执行、每次路由切换后执行
router.afterEach((to, from) => {
  console.log('afterEach',to,from);
  if (to.meta.title) {
    document.title = to.meta.title //修改网页的title
  }else{
    document.title = 'vue_test'
  }
})

2. 路由独享的守卫——路由独享的钩子函数

你可以在路由配置直接定义beforeEnter守卫,这些参数与全局前置守卫的方法参数是一样的

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

关于路由独享守卫——beforeEneter

路由独享顾名思义就是指定的路由才有这些钩子函数,通常这类路由独享的钩子函数我们是在路由配置文件中进行配置,只能设置改变前的钩子,不能设置改变后的钩子

const router = new VueRouter({ routes });

const routes = [
  {
    path: "/page1",
    component: page1,
    children: [
      {
        path: "phone",
        component: phone,
      },
      {
        path: "computer",
        component: computer,
      },
    ],
    //路由独享的钩子函数
    beforeEnter: (to, from, next) => {
      console.log(to);
      console.log(from);
      next(false);
    },
  },
];

上述代码理解为只有进入/page1才会触发beforeEnter这个钩子,如果进入其他页面,是不触发的; 

3.组件内的守卫——组件内的钩子函数

最后,你可以在路由组件内直接定义一下路由导航守卫:

  • beforeRouterEnter
  • beforeRouterUpdate
  • beforeRouterLeave
const Foo = {
  template: `...`,
  beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  },
};

关于组件内的守卫——beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

👉 
beforeRouteEnter(to,from,next)

在路由进入前调用,因为此时的vue实例还没有创建,所以beforeRouteEnter是唯一一个不能使用this的钩子函数;

to:即将要进入的路由对象;

from:正要离开的路由对象;

next:路由控制参数

👉 beforeRouteUpdate(to,from,next)

在路由发生修改的时候进行调用,比如我们上一篇文章讲到的动态路由传参,这种情况我们的beforeRouteUpdate也是会被调用的;

 to:即将要进入的路由对象;

from:正要离开的路由对象;

next:路由控制参数;

👉 beforeRouteLeave(to,from,next)

在路由离开该组件时调用;

to:即将要进入的路由对象;

from:正要离开的路由对象;

next:路由控制参数

注意:beforeRouteEnter因为触发的时候vue实例还没有创建,所以这个钩子函数中不能使用this,而beforeRouteUpdatebeforeRouteLeave都是可以访问到实例的,因为当这两个函数触发的时候实例都已经被创建了;

当调用组件内的钩子函数的时候,我们通常是在组件内部进行调用,举个例子:

​
<template>
  <div>
    <h1 id="h1">主页</h1>
    <p>
      <router-link to="/page1/phone">手机</router-link>
      <router-link to="/page1/computer">电脑</router-link>
    </p>
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  //路由进入前调用
  beforeRouteEnter(to, from, next) {
    window.document.title = "欢迎";
    next();
  },
  //路由修改时调用
  beforeRouteUpdate(to, from, next) {},
  //路由离开时调用
  beforeRouteLeave(to, from, next) {},
  data() {
    return {
      msg: "我是page1组件",
    };
  },
};
</script>


总结:

Vue Router 提供了多种路由守卫,用于在路由跳转过程中进行控制和拦截。这些路由守卫可以分为全局守卫、路由独享守卫和组件守卫。

全局守卫‌:

  • beforeEach‌:在进入路由之前进行判断,通常用于权限验证等。如果导航通过,则调用next()函数继续导航;如果需要中断当前的导航,则调用next(false);如果重定向到另一个位置,则调用next('/another-route')
  • beforeResolve‌:全局解析守卫,在所有全局前置守卫resolve之后被调用(用于在路由跳转前进行校验。),通常用于处理一些需要异步操作的情况。
  • afterEach‌:在每次路由跳转结束后被调用,通常用于一些全局的收尾工作,如埋点、页面滚动等。

路由独享守卫‌:

  • beforeEnter‌:在单个路由配置中定义的守卫,用于特定路由的特定逻辑处理。

组件守卫‌:

  • beforeRouteEnter‌:在组件实例创建之后、生命周期开始之前被调用,通常用于加载数据等。
  • beforeRouteUpdate‌(2.2版本新增):用于对动态路由进行特定处理,当路由改变但组件被复用时触发。
  • [beforeRouteLeave‌:在离开当前路由前被调用,通常用于清理工作或确认用户是否真的想离开当前页面。
    // 以下是一个简单的例子,展示了如何在Vue组件中使用beforeRouteEnter和beforeRouteLeave钩子函数:
    <template>
      <div>
        <h1>{{ msg }}</h1>
      </div>
    </template>
     
    <script>
    export default {
      data() {
        return {
          msg: 'Hello, Vue!'
        }
      },
      beforeRouteEnter(to, from, next) {
        // 在路由进入该组件的对应路由前调用
        // 无法访问this,因为当钩子函数被调用的时候,组件实例还没被创建
        next(vm => {
          // 通过`vm`访问组件实例
        });
      },
      beforeRouteLeave(to, from, next) {
        // 在路由离开该组件的对应路由前调用
        // 可以通过`this`访问组件实例
        this.someAsyncOperation().then(() => {
          next();
        });
      },
      methods: {
        someAsyncOperation() {
          // 异步操作,例如数据校验等
          return Promise.resolve();
        }
      }
    }
    </script>

这些路由守卫提供了灵活的控制机制,使得开发者可以根据应用的具体需求来定制路由跳转的行为‌。 


🔽 参考资料 

Logo

前往低代码交流专区

更多推荐