利用vue-router的navigationguard钩子函数,一些钩子函数可以让开发者根据业务逻辑控制是进行下一步还是进入指定路由。例如,后台管理页面会在进入路由前进行必要的登录和权限判断,来决定去哪条路由。以下是伪代码://全局导航守卫router.beforEach((to,from,next)=>{if('nologin'){next('/login')}elseif('admin'){next('/admin')}else{next()}})//路由配置钩子函数{path:'',component:component,beforeEnter:(to,from,next)=>{next()}}//在组件中配置钩子函数{template:'',beforeRouteEnter(to,from,next){next()}}调用next表示继续下面的流程;不调用则直接终止,导致路由中设置的组件渲染失败,页面空白。钩子函数有不同的功能,例如beforeEach、afterEach、beforeEnter、beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。对于这些已注册的钩子函数,它们必须按顺序执行,并且在必要时拥有决定是否继续执行下一个钩子函数的控制权。下面分析一下源码中的实现方法。但是,源代码中处理了许多边界条件。需要抓住核心点,去除冗余代码,精简易懂的实现。精简源码核心功能总结核心点:钩子函数注册的回调函数可以顺序执行,同时将控制权交给开发者。先来一个可以注册回调函数的类:}beforeEnter(callback){returnregisterHook(this.beforeEnterHooks,callback)}afterEach(callback){returnregisterHook(this.afterHooks,callback)}}functionregisterHook(list,fn){list.push(fn)return()=>{consti=list.indexOf(fn)if(i>-1)list.splice(i,1)}}声明的类提供beforeEach、beforeEnter和afterEach来注册必要的回调函数。抽象一个registerHook公共方法,功能:注册回调函数返回的函数,可以取消注册的回调函数使用:constrouter=newVueRouter()constbeforeEach=router.beforEach((to,from,next)=>{console.log('beforEach');next()})//未注册函数beforeEach()上面的回调函数会被取消,也就是说不会执行。router.beforEach((to,from,next)=>{console.log('beforEach');next()})router.beforeEnter((to,from,next)=>{console.log('beforeEnter');next()})router.afterEach(()=>{console.log('afterEach');})上面注册的钩子函数会依次执行。beforeEach和beforeEnter的回调接收到里面传递的参数,同时可以通过调用next继续后面的回调函数。如果不调用它们,它们将被直接终止。最后一个afterEach是在上面的回调函数执行完之后执行的,不接收任何参数。让我们先实现顺序执行。这是最简单的方法。在类中添加run方法,手动调用:classVueRouter{//...其他遗漏,添加run函数run(){//将需要顺序执行的回调存储在一个队列中letqueue=[].concat(this.beforeHooks,this.afterHooks)for(leti=0;i{})}}}}//手动调用router.run()打印:上面的'beforEach''beforeEnter'将要顺序执行的回调函数聚合在一个队列中等待执行,并传入必要的参数,但是这样开发者就无法控制是否进行下一步,即使下一个函数没有执行,队列中的函数依然会被顺序执行。改进一下:classVueRouter{//...其他遗漏,增加运行函数run(){//将需要顺序执行的回调存储在一个队列中letqueue=[].concat(this.beforeHooks,this.afterHooks)queue[0]('to','from',()=>{queue[1]('to','from',()=>{console.log('callended');})})}}router.beforEach((to,from,next)=>{console.log('beforEach');//next()})router.beforeEnter((to,from,next)=>{console.log('beforeEnter');next()})传入的下一个函数会有调用下一个回调函数的行为,控制权交给开发者。调用next函数后,会继续执行下一个回调函数;nextfunction不会被调用,那么queue的执行就终止了,所以打印出来的结果是:上面的'beforEach'实现有一个缺点,代码不够灵活,需要一个一个手动调用。在真实场景中,无法确定注册了多少个回调函数,所以需要抽象成一个功能更强大的方法:functionrunQueue(queue,fn,cb){conststep=index=>{//queue执行结束if(index>=queue.length){cb()}else{//队列有值if(queue[index]){//传入队列中的回调,做一些必要的操作,第二个参数为下一个回调函数fn(queue[index],()=>{step(index+1)})}else{step(index+1)}}}//初始调用,从第一个开始第一步(0)}runQueue是执行队列的一般方法。第一个参数是回调函数队列,依次取出;第二个参数是函数,接受队列中的函数,并进行一些其他处理;并且可以执行以下回调函数的执行;第三个参数在队列执行结束后调用。知道这个函数的含义,我们来使用它:classVueRouter{//...其他遗漏,添加运行函数run(){//将需要顺序执行的回调存储在一个队列中letqueue=[].concat(this.beforeHooks,this.beforeEnterHooks)//接收回函数,继续执行下一个函数constiterator=(hook,next)=>{//传递给回调函数的参数,第三个参数为函数,exchange调用给开发者,调用之后,下一个hook('to','from',()=>{console.log('执行下一个回调时,处理一些相关信息');next()})}runQueue(queue,iterator,()=>{console.log('Endofexecution');//执行afterEach中的回调函数this.afterHooks.forEach((fn)=>{fn()})})}}//注册router.beforEach((to,from,next)=>{console.log('beforEach');next()})router.beforeEnter((to,from,next)=>{console.log('beforeEnter');next()})router.afterEach(()=>{console.log('afterEach');})router.run();从上面的代码可以看出,每次把queue队列中的回调函数传给iterator,用hook接收,调用。给钩子传递必要的参数,尤其是第三个参数,开发者在注册的回调函数中调用,控制下一步。队列执行完成后,不传入任何参数,依次执行afterHooks的回调函数。所以打印的结果是:当beforeEach执行下一个回调时,处理一些相关信息beforeEnter执行下一个回调,执行完afterEach处理一些相关信息。会开悟。以上如有出入,敬请指正,学习,谢谢。~~~~github博客地址:https://github.com/WYseven/blog,欢迎star。如果对您有帮助,请关注【前端技能解锁】: