<em id="09ttv"></em>
    <sup id="09ttv"><pre id="09ttv"></pre></sup>
    <dd id="09ttv"></dd>

        • vue-router 導(dǎo)航守衛(wèi)中 next 控制實(shí)現(xiàn)

          2020-5-14    seo達(dá)人

          使用 vue-router 的導(dǎo)航守衛(wèi)鉤子函數(shù),某些鉤子函數(shù)可以讓開(kāi)發(fā)者根據(jù)業(yè)務(wù)邏輯,控制是否進(jìn)行下一步,或者進(jìn)入到指定的路由。


          例如,后臺(tái)管理頁(yè)面,會(huì)在進(jìn)入路由前,進(jìn)行必要登錄、權(quán)限判斷,來(lái)決定去往哪個(gè)路由,以下是偽代碼:


          // 全局導(dǎo)航守衛(wèi)

          router.beforEach((to, from, next) => {

           if('no login'){

             next('/login')

           }else if('admin') {

             next('/admin')

           }else {

             next()

           }

          })


          // 路由配置鉤子函數(shù)

          {

           path: '',

           component: component,

           beforeEnter: (to, from, next) => {

             next()

           }

          }


          // 組件中配置鉤子函數(shù)

          {

           template: '',

           beforeRouteEnter(to, from, next) {

             next()

           }

          }

          調(diào)用 next,意味著繼續(xù)進(jìn)行下面的流程;不調(diào)用,則直接終止,導(dǎo)致路由中設(shè)置的組件無(wú)法渲染,會(huì)出現(xiàn)頁(yè)面一片空白的現(xiàn)象。


          鉤子函數(shù)有不同的作用,例如 beforEach,afterEach,beforeEnter,beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave,針對(duì)這些注冊(cè)的鉤子函數(shù),要依次進(jìn)行執(zhí)行,并且在必要環(huán)節(jié)有控制權(quán)決定是否繼續(xù)進(jìn)入到下一個(gè)鉤子函數(shù)中。


          以下分析下源碼中實(shí)現(xiàn)的方式,而源碼中處理的邊界情況比較多,需要抓住核心點(diǎn),去掉冗余代碼,精簡(jiǎn)出便于理解的實(shí)現(xiàn)。


          精簡(jiǎn)源碼核心功能

          總結(jié)下核心點(diǎn):鉤子函數(shù)注冊(cè)的回調(diào)函數(shù),能順序執(zhí)行,同時(shí)會(huì)將控制權(quán)交給開(kāi)發(fā)者。


          先來(lái)一個(gè)能夠注冊(cè)回調(diào)函數(shù)的類:


          class VueRouter {

           constructor(){

             this.beforeHooks = []

             this.beforeEnterHooks = []


             this.afterHooks = []

           }


           beforEach(callback){

             return registerHook(this.beforeHooks, callback)

           }

           beforeEnter(callback){

             return registerHook(this.beforeEnterHooks, callback)

           }

           afterEach(callback){

             return registerHook(this.afterHooks, callback)

           }

          }

          function registerHook (list, fn) {

           list.push(fn)

           return () => {

             const i = list.indexOf(fn)

             if (i > -1) list.splice(i, 1)

           }

          }

          聲明的類,提供了 beforEach 、beforeEnter 和 afterEach 來(lái)注冊(cè)必要的回調(diào)函數(shù)。


          抽象出一個(gè) registerHook 公共方法,作用:


          注冊(cè)回調(diào)函數(shù)

          返回的函數(shù),可以取消注冊(cè)的回調(diào)函數(shù)

          使用一下:


          const router = new VueRouter()


          const beforEach = router.beforEach((to, from, next) => {

           console.log('beforEach');

           next()

          })

          // 取消注冊(cè)的函數(shù)

          beforEach()

          以上的回調(diào)函數(shù)會(huì)被取消,意味著不會(huì)執(zhí)行了。



          router.beforEach((to, from, next) => {

           console.log('beforEach');

           next()

          })


          router.beforeEnter((to, from, next) => {

           console.log('beforeEnter');

           next()

          })


          router.afterEach(() => {

           console.log('afterEach');

          })

          以上注冊(cè)的鉤子函數(shù)會(huì)依次執(zhí)行。beforEach 和 beforeEnter 的回調(diào)接收內(nèi)部傳來(lái)的參數(shù),同時(shí)通過(guò)調(diào)用 next 可繼續(xù)走下面的回調(diào)函數(shù),如果不調(diào)用,則直接被終止了。

          最后一個(gè) afterEach 在上面的回調(diào)函數(shù)都執(zhí)行后,才被執(zhí)行,且不接收任何參數(shù)。


          先來(lái)實(shí)現(xiàn)依次執(zhí)行,這是最簡(jiǎn)單的方式,在類中增加 run 方法,手動(dòng)調(diào)用:



          class VueRouter {

           // ... 其他省略,增加 run 函數(shù)


           run(){

             // 把需要依次執(zhí)行的回調(diào)存放在一個(gè)隊(duì)列中

             let queue = [].concat(

               this.beforeHooks,

               this.afterHooks

             )

             

             for(let i = 0; i < queue.length; i++){

               if(queue(i)) {

                 queue(i)('to', 'from', () => {})

               }

             }

           }

          }


          // 手動(dòng)調(diào)用


          router.run()

          打印:


          'beforEach'

          'beforeEnter'

          上面把要依次執(zhí)行的回調(diào)函數(shù)聚合在一個(gè)隊(duì)列中執(zhí)行,并傳入必要的參數(shù),但這樣開(kāi)發(fā)者不能控制是否進(jìn)行下一步,即便不執(zhí)行 next 函數(shù),依然會(huì)依次執(zhí)行完隊(duì)列的函數(shù)。


          改進(jìn)一下:


          class VueRouter {

           // ... 其他省略,增加 run 函數(shù)


           run(){

             // 把需要依次執(zhí)行的回調(diào)存放在一個(gè)隊(duì)列中

             let queue = [].concat(

               this.beforeHooks,

               this.afterHooks

             )

             queue[0]('to', 'from', () => {

               queue[1]('to', 'from', () => {

                console.log('調(diào)用結(jié)束');

               })

             })

           }

          }


          router.beforEach((to, from, next) => {

           console.log('beforEach');

           // next()

          })


          router.beforeEnter((to, from, next) => {

           console.log('beforeEnter');

           next()

          })

          傳入的 next 函數(shù)會(huì)有調(diào)用下一個(gè)回調(diào)函數(shù)的行為,把控制權(quán)交給了開(kāi)發(fā)者,調(diào)用了 next 函數(shù)會(huì)繼續(xù)執(zhí)行下一個(gè)回調(diào)函數(shù);不調(diào)用 next 函數(shù),則終止了隊(duì)列的執(zhí)行,所以打印結(jié)果是:


          'beforEach'

          上面實(shí)現(xiàn)有個(gè)弊端,代碼不夠靈活,手動(dòng)一個(gè)個(gè)調(diào)用,在真實(shí)場(chǎng)景中無(wú)法確定注冊(cè)了多少個(gè)回調(diào)函數(shù),所以需要繼續(xù)抽象成一個(gè)功能更強(qiáng)的方法:


          function runQueue (queue, fn, cb) {

           const step = index => {

             // 隊(duì)列執(zhí)行結(jié)束了

             if (index >= queue.length) {

               cb()

             } else {

               // 隊(duì)列有值

               if (queue[index]) {

                 // 傳入隊(duì)列中回調(diào),做一些必要的操作,第二個(gè)參數(shù)是為了進(jìn)行下一個(gè)回調(diào)函數(shù)

                 fn(queue[index], () => {

                   step(index + 1)

                 })

               } else {

                 step(index + 1)

               }

             }

           }

           // 初次調(diào)用,從第一個(gè)開(kāi)始

           step(0)

          }

          runQueue 就是執(zhí)行隊(duì)列的通用方法。


          第一個(gè)參數(shù)為回調(diào)函數(shù)隊(duì)列, 會(huì)依次取出來(lái);

          第二個(gè)參數(shù)是函數(shù),它接受隊(duì)列中的函數(shù),進(jìn)行一些其他處理;并能進(jìn)行下個(gè)回調(diào)函數(shù)的執(zhí)行;

          第三個(gè)參數(shù)是隊(duì)列執(zhí)行結(jié)束后調(diào)用。

          知道了這個(gè)函數(shù)的含義,來(lái)使用一下:



          class VueRouter {

           // ... 其他省略,增加 run 函數(shù)


           run(){

             // 把需要依次執(zhí)行的回調(diào)存放在一個(gè)隊(duì)列中

             let queue = [].concat(

               this.beforeHooks,

               this.beforeEnterHooks

             )


             // 接收回到函數(shù),和進(jìn)行下一個(gè)的執(zhí)行函數(shù)

             const iterator = (hook, next) => {

               // 傳給回調(diào)函數(shù)的參數(shù),第三個(gè)參數(shù)是函數(shù),交給開(kāi)發(fā)者調(diào)用,調(diào)用后進(jìn)行下一個(gè)

               hook('to', 'from', () => {

                 console.log('執(zhí)行下一個(gè)回調(diào)時(shí),處理一些相關(guān)信息');

                 next()

               })

             }


             runQueue(queue, iterator, () => {


               console.log('執(zhí)行結(jié)束');

               // 執(zhí)行 afterEach 中的回調(diào)函數(shù)

               this.afterHooks.forEach((fn) => {

                 fn()

               })

             })

           }

          }

          // 注冊(cè)

          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();

          從上面代碼可以看出來(lái),每次把隊(duì)列 queue 中的回調(diào)函數(shù)傳給 iterator , 用 hook 接收,并調(diào)用。

          傳給 hook 必要的參數(shù),尤其是第三個(gè)參數(shù),開(kāi)發(fā)者在注冊(cè)的回調(diào)函數(shù)中調(diào)用,來(lái)控制進(jìn)行下一步。

          在隊(duì)列執(zhí)行完畢后,依次執(zhí)行 afterHooks 的回調(diào)函數(shù),不傳入任何參數(shù)。


          所以打印結(jié)果為:


          beforEach

          執(zhí)行下一個(gè)回調(diào)時(shí),處理一些相關(guān)信息

          beforeEnter

          執(zhí)行下一個(gè)回調(diào)時(shí),處理一些相關(guān)信息

          執(zhí)行結(jié)束

          afterEach

          以上實(shí)現(xiàn)的非常巧妙,再看 Vue-router 源碼這塊的實(shí)現(xiàn)方式,相信你會(huì)豁然開(kāi)朗。

          日歷

          鏈接

          個(gè)人資料

          存檔

          国产精品九九久久免费视频 | 久久久久青草线蕉综合超碰 | 久久精品久久久久观看99水蜜桃| 久久人人超碰精品CAOPOREN| 思思久久好好热精品国产| 亚洲精品无码久久久影院相关影片| 亚洲va国产va天堂va久久| 热久久这里只有精品| 狠狠色丁香婷婷久久综合 | 久久国产成人精品麻豆| 久久久久亚洲av毛片大| 久久久久无码精品国产不卡| 久久久青草青青国产亚洲免观| 久久亚洲熟女cc98cm| 99热精品久久只有精品| 久久婷婷成人综合色综合| 午夜精品久久久久久| 国产精品视频久久久| 亚洲欧洲中文日韩久久AV乱码| 精品久久久久久无码中文字幕一区| 久久久久免费视频| 麻豆精品久久精品色综合| 99久久精品免费看国产一区二区三区 | 久久成人国产精品一区二区| 久久狠狠爱亚洲综合影院| 亚洲国产精品婷婷久久| 久久人人爽人人爽人人片AV不| 久久婷婷人人澡人人| 久久这里只有精品久久| 精品国产乱码久久久久久郑州公司 | A级毛片无码久久精品免费| 亚洲国产精品综合久久一线| 国内精品久久久久久久亚洲| 国内精品久久久久久久久电影网 | 国产ww久久久久久久久久| 久久综合久久久| 久久国产精品免费一区二区三区| 久久久综合香蕉尹人综合网| 奇米影视7777久久精品人人爽| 精品久久久久久99人妻| 国产成人综合久久综合|