老规矩,先来解读下官方文档:

vue-router提供的导航守卫主要用来通过跳转或取消的方式来守卫导航。( 简单说,导航守卫就是在路由跳转的时候的一些钩子函数,当从一个页面跳转到另一个页面时,可以在跳转前、中、后做一些事情,我们可以控制路由的跳转 )。

 

导航守卫可分为 三大类:( 全局守卫、路由专享守卫、组件守卫)

一、全局守卫又可分为三个:

(1)全局前置守卫:(项目必用!!!)

router.beforeEach( to,from,next ) =>{ }

(2)全局解析守卫:

router.beforeResolve( to,from,next ) =>{ }

(3)全局后置守卫:

router.afterEach( to,from )=>{ }

二、路由专享守卫:

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

三、组件中的守卫:

(1)beforeRouteEnter

(2)beforeRouteUpdate

(3)beforeRouteLeave

export default {
    name:'play',
    beforeRouteEnter(to,from,next){

    },
    beforeRouteUpdate(to,from,next){

    },
    beforeRouteLeave(to,from,next){

    }
}

****************** 详解 ***********************************

全局前置守卫 router.beforeEach( ( to,from,next)=>{ } ):

1、常用于登录验证;

2、使用 router.beforeEach 可注册一个全局前置守卫;

3、每当一个导航被触发时,首先被调用的总是全局前置守卫 ;

4、该守卫接受三个参数:to、from、next,三个参数意思分别是:

   to —— 即将要进入的目标路由对象(路由对象);

   from —— 当前导航正要离开的路由(路由对象);

   next —— 此方法,必须调用,如果想跳转的话,否则路由将不会跳转(function)。

router.beforeEach((to,from,next)=>{
    console.log(to)
    console.log(from)
    console.log(next)
    next()
})

上边代码,我们分别打印下这三个参数看下:

从首页(根路径)路由名字为first的页面 跳转到 路由名字 为play页面;

to :正是跳转后的目标路有对象play;

 

to.path 和to.fullPath的区别:

to.path - 当前的路径,始终解析为绝对路径;to.fullPath - 完整的解析URL包含查询参数和哈希。

 

from:是之前的路由对象 first。

 

next:则是一个函数,next函数决定路由是否跳转;

 

 

next( ) 参数问题:

next( false) 可传false,当用户点击浏览器后退按钮时,url地址会重置到from路由对象的地址(通俗说,就是路由不会跳转了!!!)

next( "/")或者 next({path:"/"})可以传路径,它会跳转到不同地址。例如:下边当用户访问路由名为play对应的页面时候,它会被终止,直接会被重定向到路径为 “ /news ” 的页面。

router.beforeEach((to,from,next)=>{
    if(to.name == "play"){
        next({path:"/news"})
    }
    next()
})

全局解析守卫 router.beforeResolve( ( to,from,next)=>{ } )

官方文档:2.5.0新增的一个守卫,在导航被确认之前同时在所有组件守卫和异步路由被解析之后(加载完之后),解析守卫会被调用。。。

 

全局后置钩子router.afterEach( ( to,from)=>{ } )

与守卫不同的是,此钩子函数不会接受next函数,也不会改变导航本身。。。是在全局解析守卫之后被调用。。。

 

路由独享守卫beforeEnter : ( to,from,next)=>{ } 

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

 

组件内守卫beforeRouterEnter : ( to,from,next)=>{ }

export default {
    name:'play',
    beforeRouteEnter(to,from,next){
      // 在渲染组件前调用,不能获取this,组件实例还未被挂载
        next()
    },
    beforeRouteUpdate(to,from,next){
      // 在当前路由改变,但当前组件被复用时调用, 
      // 比如:带有动态参数的路径,/foo/1  跳转  /foo/2 时,
      // 该钩子函数被调用。(可访问组件实例this) 
        next()
    },
    beforeRouteLeave(to,from,next){
     // 离开该组件对应的路由时,该钩子函数会被调用
        next()
    }
}  

beforeRouterEnter  守卫不能够访问this,因为守卫在导航确认前被掉用,即将登场的新组件还未被创建。。。

当然如果你非要在此守卫中用到this,官方也给出了一个方法,你可以在next函数中传一个回调函数,并把实例作为参数传到回调函数中去,这样您就可以使用this了!!!!(补充下:next中的回调在组件加载完之后执行,最后我整理了一张完整的执行顺序图)

export default {
    name:'play',
    beforeRouteEnter(to,from,next){
        next((_this)=>{
            // 通过 _this来访问实例
        })
    }
}

《《《官方提醒》》》

beforeRouterEnter是支持给next函数传递回调的唯一守卫;

对于beforeRouterUpdate守卫 和 beforeRouterLeave守卫来说,this已经可以用了,所以不支持传递回调,也没意义!!!

 

组件内守卫beforeRouterUpdate : ( to,from,next)=>{ } 

下边例子中,路由页 "/news/:xxx" 会被复用,beforeRouterUpdate 守卫会被触发!!!

<template>
  <div>
    <div v-for="item in my_data" :key="item.id">
      <router-link :to="'/news/' +item.id">{{item.name}}</router-link>
    </div>
    <h1>{{this.$route.params.id}}</h1>
  </div>
  
</template>

<script>
export default {
    name: "news",
    data() {
        return {
            my_data: [
                { name: "java", id: "1" },
                { name: "python", id: "2" },
                { name: "javascript", id: "3" }
            ]
        };
    },
    beforeRoutEnter(to,from,next){
        console.log('news中组件内部钩子函数——beforeRouteUpdate')
        next()
    },
    beforeRouteUpdate(to,from,next){
        console.log('news中组件内部钩子函数——beforeRouteUpdate')
        next()
    },
    beforeRouteLeave(to,from,next){
        console.log('组件内部钩子函数——beforeRouteLeave)
        next()
    },
};
</script>
const router = new VueRouter({
  routes:[
    {
       path:'/news/:id',
       component:News,
       beforeEnter:(to,from,next)=>{
         console.log('news路由中的 路由独享钩子函数——beforeEnter')
         next()
       }
    }
  ]
})
router.beforeEach((to,from,next)=>{
    console.log('全局守卫——beforeEach')
    next()
})
router.beforeResolve((to,from,next)=>{
    console.log('全局守卫——beforeResolve')
    next()
})
router.afterEach((to,from)=>{
    console.log('全局守卫——afterEach')
})

上边代码有几个注意点:

1、从一个普通组件,切换到一个可复用的组件,先来看下执行顺序:

2、当切换可复用的页面时,也就是从 "/news/:1"  ——> "/news/:2"  ——> "/news/:3"  时,执行顺序:(路由独享守卫和组件内钩子beforeRouteEnter 不再执行!)

 

组件内守卫  beforeRouterLeave: ( to,from,next)=>{ } 

此守卫是在从一个导航切换到另一个导航之后,才执行的。。。通常在此守卫可以做一些禁止用户离开的操作,比如:还未保存的草稿;或者在用户离开此导航时清除setInterval计时器,防止离开之后,计时器还在被调用等等。

router.beforeEach((to,from,next)=>{
    if("用户草稿保存了"){
        next() //允许跳转
    }else{
        next(false) //否则禁止跳转
    }
})

总结:

7个守卫以及生命周期函数执行顺序:

 

 

 

Logo

前往低代码交流专区

更多推荐