国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

一篇搞定vue-Router導(dǎo)航守衛(wèi)

不知名網(wǎng)友 / 3280人閱讀

摘要:如果我們不掉用守衛(wèi)中的,迭代器的肯定并不會(huì)執(zhí)行,守衛(wèi)的迭代就停止了,守衛(wèi)堵塞并不會(huì)執(zhí)行完畢,也就不會(huì)由后面的更細(xì)路由操作了。

vue-router導(dǎo)航守衛(wèi)

在本期文章中,我將為大家梳理弄明白以下幾個(gè)事情,

1:導(dǎo)航守衛(wèi)的執(zhí)行順序是怎么樣的? 2:導(dǎo)航守衛(wèi)中的next的用處? 3:為什么afterEach守衛(wèi)沒有next? 4:beforeEach是否可以疊加? 5:路由跳轉(zhuǎn)經(jīng)歷了哪幾部分?

在之前說(shuō)過(guò)的一個(gè)內(nèi)容router實(shí)例的history屬性幫助我們做了所有跳轉(zhuǎn)部分的事情,所以導(dǎo)航守衛(wèi)的內(nèi)容也在history中。

我們以HTML5History這個(gè)類來(lái)看一下這個(gè)push方法,

push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
    const { current: fromRoute } = this
    this.transitionTo(location, route => {
      pushState(cleanPath(this.base + route.fullPath))
      handleScroll(this.router, route, fromRoute, false)
      onComplete && onComplete(route)
    }, onAbort)
  }

push(我們跳轉(zhuǎn)時(shí)的$router.push就是這個(gè)方法)過(guò)程中調(diào)用了transitionTo完成了一系列的跳轉(zhuǎn)內(nèi)容,但這個(gè)方法在HTML5的類中并不存在,繼承于base.js類中的方法
transitionTo就是實(shí)現(xiàn)路由跳轉(zhuǎn)的方法
transitionTo的主流程是由confirmTranstion方法于uodateRoute方法結(jié)合起來(lái)的,翻譯成普通話:路由跳轉(zhuǎn)要先經(jīng)過(guò)一個(gè)確認(rèn)跳轉(zhuǎn)的過(guò)程,在確認(rèn)過(guò)程完成后進(jìn)行一次路由的更新操作,

transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {
    // 獲取要跳轉(zhuǎn)的并且經(jīng)過(guò)處理的路由
    const route = this.router.match(location, this.current)
    // confirmTranstion確認(rèn)跳轉(zhuǎn)過(guò)程
    this.confirmTransition(route, () => {
      // 確認(rèn)完畢后完成更新路由操作
      this.updateRoute(route)
      onComplete && onComplete(route)
      this.ensureURL()

      // fire ready cbs once
      if (!this.ready) {
        this.ready = true
        this.readyCbs.forEach(cb => { cb(route) })
      }
    }, err => {
      if (onAbort) {
        onAbort(err)
      }
      if (err && !this.ready) {
        this.ready = true
        this.readyErrorCbs.forEach(cb => { cb(err) })
      }
    })
  }

confirmTransiton做了什么呢?首先判斷一下你是不是相同的路由。如果是那就什么都不做,第二步呢,我們要開始收集一波守衛(wèi)了,然后把守衛(wèi)收集起來(lái),然后把每個(gè)守衛(wèi)執(zhí)行一遍,confirmTransition就算執(zhí)行成功了。

下面是部分源碼截圖:

這個(gè)過(guò)程中的難點(diǎn)是什么?

如何收集守衛(wèi)組合成守衛(wèi)隊(duì)列? 如何按順序執(zhí)行守衛(wèi)的同時(shí)可以隨時(shí)中止守衛(wèi)隊(duì)列? 如何找到守衛(wèi)隊(duì)列執(zhí)行完畢后的那個(gè)節(jié)點(diǎn)(守衛(wèi)隊(duì)列執(zhí)行完可以通知一下)

在vue-router中封裝了一個(gè)runQueue函數(shù)來(lái)解決上面的三個(gè)問(wèn)題的后兩個(gè)。第一個(gè)問(wèn)題呢則涉及到vue-router處理路由的一個(gè)大篇章,我們著重講一下runQueue函數(shù)

runQueue函數(shù)的思想:

1:迭代器模式來(lái)保證遍歷隊(duì)列時(shí)每一步都是可控的,

2:隊(duì)列完成后執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù),

推斷出函數(shù)參數(shù)的對(duì)應(yīng)功能:

queue : 需要執(zhí)行的守衛(wèi)隊(duì)列

fn : 迭代器函數(shù),守衛(wèi)隊(duì)列的每一個(gè)守衛(wèi)都去執(zhí)行迭代器函數(shù)

fn的第二個(gè)參數(shù)使迭代器進(jìn)入下一步,不掉用就不會(huì)進(jìn)入下一步(很重點(diǎn))

cb : 結(jié)束時(shí)調(diào)用的回調(diào)函數(shù)

export function runQueue (queue: Array, fn: Function, cb: Function) {
  const step = index => {
  // 隊(duì)列里已經(jīng)沒有內(nèi)容可以執(zhí)行了,那就代表隊(duì)列執(zhí)行完成了
    if (index >= queue.length) {
      cb()
    } else {
      // 如果隊(duì)列內(nèi)容存在就執(zhí)行迭代函數(shù)
      if (queue[index]) {
        fn(queue[index], () => {
          step(index + 1)
        })
      // 什么也沒有那就到下一步了        
      } else {
        step(index + 1)
      }
    }
  }
  // 啟動(dòng)了
  step(0)
}

runQueue是怎么幫助我們解決守衛(wèi)隊(duì)列處理的問(wèn)題就算說(shuō)完了。

(快留起來(lái),這函數(shù)簡(jiǎn)直吊極了?。?/b>

處理守衛(wèi)隊(duì)列的大錘子我們已經(jīng)制造好了,可以開工了,那你的守衛(wèi)隊(duì)列呢??

對(duì)對(duì)對(duì),還有守衛(wèi)隊(duì)列要收集。
這個(gè)時(shí)候我們要想想有哪些守衛(wèi)?

守衛(wèi)有兩大種類:前置守衛(wèi)、后置守衛(wèi)。

前置守衛(wèi):

全局的前置守衛(wèi): beforeEach beforeResolve

路由獨(dú)享的守衛(wèi): beforeEnter

組件內(nèi)的守衛(wèi): beforeRouterEnter、beforeRouterUpdate、beforeRouteLeave

后置守衛(wèi):

全局的后置守衛(wèi): afterEach

我們要想一下這些守衛(wèi)都是怎么注冊(cè)的,

在路由實(shí)例注冊(cè)的:

beforeEach、beforeResolve、afterEach

在路由配置中注冊(cè)的(路由獨(dú)享守衛(wèi)):

beforeEnter

組件內(nèi)的路由守衛(wèi):

beforeRouteLeave、beforeRouteUpdate、beforeRouteEnter

好了我們要去榨取對(duì)應(yīng)的守衛(wèi)了,

confirmTransition的守衛(wèi)分為兩個(gè)隊(duì)列:我們先來(lái)看第一個(gè)隊(duì)列

 // 拿到路由跳轉(zhuǎn)中更新、摧毀、激活時(shí)對(duì)應(yīng)展示的組件。
 const {
      updated,
      deactivated,
      activated
    } = resolveQueue(this.current.matched, route.matched)
    // 路由守衛(wèi)
    const queue: Array = [].concat(
      // in-component leave guards
      extractLeaveGuards(deactivated),
      // global before hooks
      this.router.beforeHooks,
      // in-component update hooks
      extractUpdateHooks(updated),
      // in-config enter guards
      activated.map(m => m.beforeEnter),
      // async components
      resolveAsyncComponents(activated)
    )

一個(gè)queue的順序:

拿到被摧毀的組件的,榨取出所有組件內(nèi)的離開守衛(wèi)。

全局的beforeEach組件。

拿到更新的所有組件,榨取出所有組件內(nèi)的更新守衛(wèi)。

遍歷要進(jìn)入的路由,拿到所有路由的獨(dú)享守衛(wèi)。

加載要被激活的異步組件

7個(gè)守衛(wèi)中的4個(gè)守衛(wèi)都在被按順序拿出來(lái)了,放入第一個(gè)queue。

再下一步要有一個(gè)處理守衛(wèi)的迭代器:

我們?cè)撊绾翁幚硎匦l(wèi)?

保證在守衛(wèi)中可以停止并且跳轉(zhuǎn)到其余路由,

保證守衛(wèi)可以正常通過(guò),

const iterator = (hook: NavigationGuard, next) => {
      if (this.pending !== route) {
        return abort()
      }
      try {
        hook(route, current, (to: any) => {
          // 傳個(gè)false就直接執(zhí)行路由的錯(cuò)誤處理,然后停止什么都不做。
          if (to === false || isError(to)) {
            // next(false) -> abort navigation, ensure current URL
            this.ensureURL(true)
            abort(to)
          } else if (
          // 如果我們接受了一個(gè)可以操作的路徑。
            typeof to === "string" ||
            (typeof to === "object" && (
              typeof to.path === "string" ||
              typeof to.name === "string"
            ))
          ) {
            // next("/") or next({ path: "/" }) -> redirect
            abort()
            // 我們就執(zhí)行路由跳轉(zhuǎn)操作,并且守衛(wèi)隊(duì)列停止下面的迭代
            if (typeof to === "object" && to.replace) {
              this.replace(to)
            } else {
              this.push(to)
            }
          } else {
            // confirm transition and pass on the value
            // 接續(xù)迭代下去咯
            next(to)
          }
        })
      } catch (e) {
        abort(e)
      }
    }

next函數(shù),之前在將runQueue的函數(shù)的時(shí)候,fn接收第二個(gè)參數(shù)(之前畫過(guò)重點(diǎn)),第二個(gè)參數(shù)的回調(diào)函數(shù)是完成迭代器向下一步執(zhí)行的功能。

下面會(huì)有一點(diǎn)亂:

所有的前置守衛(wèi)都接收三個(gè)參數(shù)

beforeEnter(to,from,next)=>{
    //這個(gè)next就是我們看到的 hook里面接收的箭頭函數(shù)((to:any)=>{})
    //這個(gè)箭頭函數(shù)里面對(duì)迭代器的next進(jìn)行了一下掉用,
    //保證在一定情況下迭代器可以向下走一步。
    next("/index")
    // 我們?cè)谶@種next("/index")傳遞一個(gè)可以執(zhí)行的路徑時(shí),(to:any)=>{}
    //這個(gè)箭頭函數(shù)并不會(huì)調(diào)用迭代的next,而是跳轉(zhuǎn)別的路徑執(zhí)行了push操作。
    // 如果我們不掉用守衛(wèi)中的next,迭代器的next肯定并不會(huì)執(zhí)行,守衛(wèi)的迭代就停止了,
    // 守衛(wèi)堵塞confirmTransition并不會(huì)執(zhí)行完畢,也就不會(huì)由后面的更細(xì)路由操作了。
}
runQueue(queue, iterator, () => {
      const postEnterCbs = []
      const isValid = () => this.current === route
      // wait until async components are resolved before
      // extracting in-component enter guards
      const enterGuards = extractEnterGuards(activated, postEnterCbs, isValid)
      const queue = enterGuards.concat(this.router.resolveHooks)
      runQueue(queue, iterator, () => {
        if (this.pending !== route) {
          return abort()
        }
        this.pending = null
        onComplete(route)
        if (this.router.app) {
          this.router.app.$nextTick(() => {
            postEnterCbs.forEach(cb => { cb() })
          })
        }
      })
    })

我們?cè)诎训谝粋€(gè)queue(四個(gè)守衛(wèi)與一個(gè)異步組件的加載)執(zhí)行完畢后,要收集與執(zhí)行第二個(gè)queue了,

第二個(gè)queue:

收集了被的激活組件內(nèi)的進(jìn)入守衛(wèi)

全局的beforeResolve的守衛(wèi)

收集完開始執(zhí)行第二個(gè)queue的迭代。第二個(gè)queue執(zhí)行完執(zhí)行一下onComplete函數(shù),代表著confirmTransition方法執(zhí)行完畢了。確認(rèn)路由的過(guò)程結(jié)束了,

下面就是updateRoute的過(guò)程。updateRoute的時(shí)候執(zhí)行全部的后置守衛(wèi),因?yàn)楦侣酚芍?,?dāng)前的路由已經(jīng)變化了,所以在給守衛(wèi)傳參數(shù)的時(shí)候緩存了一下,之前的路由。

updateRoute (route: Route) {
    const prev = this.current
    this.current = route
    this.cb && this.cb(route)
    this.router.afterHooks.forEach(hook => {
      hook && hook(route, prev)
    })
  }

所以為什么afterEach沒有next呢?因?yàn)閍fterEach根本不在迭代器之內(nèi),他就沒有next來(lái)觸發(fā)迭代器的下一步。

最后我們說(shuō)一下beforeEach的內(nèi)容:
我們?cè)O(shè)置beforeEach全局守衛(wèi)的時(shí)候,守衛(wèi)們存儲(chǔ)在哪里?

beforeEach (fn: Function): Function {
    return registerHook(this.beforeHooks, fn)
}
function registerHook (list: Array, fn: Function): Function {
  list.push(fn)
  // 返回值是一個(gè)function
  return () => {
    const i = list.indexOf(fn)
    if (i > -1) list.splice(i, 1)
  }
}

這段代碼beforeEach是通過(guò)注冊(cè)守衛(wèi)的方式,將注冊(cè)的全局前置守衛(wèi)放在beforeHooks的容器內(nèi),這個(gè)容器里面裝載著所有的前置守衛(wèi)

一家人(全局的 前置進(jìn)入、前置resolve、后置守衛(wèi))整整齊齊的放在對(duì)應(yīng)的容器里面,容器是個(gè)數(shù)組,所以注冊(cè)全局守衛(wèi)的時(shí)候,是支持注冊(cè)多個(gè)的,

router.beforeEach(()=>{xxx});
router.beforeEach(()=>{yyy});
// 這兩個(gè)守衛(wèi)都會(huì)執(zhí)行,只是先注冊(cè)的先執(zhí)行,
// registerHook這個(gè)方法還可以清除對(duì)應(yīng)的守衛(wèi),這個(gè)方法也可以使用
總結(jié)

我們來(lái)回答一下開篇的5個(gè)問(wèn)題

1:導(dǎo)航守衛(wèi)的執(zhí)行順序是怎么樣的?

beforeRouteLeave < beforeEach < beforeRouteUpdate < beforeEnter < beforeRouteEnter < beforeResolve < afterEach

2:導(dǎo)航守衛(wèi)中的next的用處?

next的作用,使導(dǎo)航守衛(wèi)隊(duì)列的繼續(xù)向下迭代

3:為什么afterEach守衛(wèi)沒有next?

afterEach根本不在導(dǎo)航守衛(wèi)隊(duì)列內(nèi),沒有迭代的next

4:beforeEach是否可以疊加?

beforeEach是可以疊加的,所有的全局前置守衛(wèi)按順序存放在beforeHooks的數(shù)組里面,

5:路由跳轉(zhuǎn)經(jīng)歷了哪幾部分?

路由跳轉(zhuǎn)的核心方法是transitionTo,在跳轉(zhuǎn)過(guò)程中經(jīng)歷了一次confirmTransition,

(beforeRouteLeave < beforeEach < beforeRouteUpdate < beforeEnter < 異步組件加載)這樣順序的queue為第一個(gè),

在第一個(gè)queue迭代完畢后,執(zhí)行第二個(gè)(beforeRouteEnter < beforeResolve)這樣順序的queue,

在執(zhí)行完畢后,開始執(zhí)行updateRoute,之后執(zhí)行全局的afterEach守衛(wèi)。最后完成路由的跳轉(zhuǎn)。

5個(gè)問(wèn)題解答完畢,希望對(duì)你的業(yè)務(wù)有幫助。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/98088.html

相關(guān)文章

  • Vue-router進(jìn)階:導(dǎo)航守衛(wèi)

    摘要:全局前置守衛(wèi)使用注冊(cè)一個(gè)全局前置守衛(wèi)。守衛(wèi)是異步解析執(zhí)行,此時(shí)導(dǎo)航在所有守衛(wèi)完之前一直處于等待中。中斷當(dāng)前的導(dǎo)航。不過(guò)可以通過(guò)傳一個(gè)回調(diào)函數(shù)來(lái)訪問(wèn)組建實(shí)例。注意是支持傳遞回調(diào)的唯一守衛(wèi)。用創(chuàng)建好的實(shí)例調(diào)用守衛(wèi)中傳給的回調(diào)函數(shù)。 全局前置守衛(wèi) 使用router.beforeEach注冊(cè)一個(gè)全局前置守衛(wèi)。 const router = new VueRouter({...}) router...

    tommego 評(píng)論0 收藏0
  • JS每日一題:Vue-router有哪些鉤子?使用場(chǎng)景?

    摘要:?jiǎn)栍心男┿^子使用場(chǎng)景的實(shí)現(xiàn)可以點(diǎn)這里前面我們用大白話講過(guò)什么是鉤子,這里在重復(fù)一下,就是在什么什么之前什么什么之后英文叫專業(yè)點(diǎn)叫生命周期,裝逼點(diǎn)可以叫守衛(wèi)中也存在鉤子的概念分為三步記憶全局守衛(wèi)路由獨(dú)享守衛(wèi)組件獨(dú)享守衛(wèi)全局守衛(wèi)很好理解,全 20190218問(wèn) Vue-router有哪些鉤子?使用場(chǎng)景? router的實(shí)現(xiàn)可以點(diǎn)這里 前面我們用大白話講過(guò)什么是鉤子,這里在重復(fù)一下,就是在...

    張金寶 評(píng)論0 收藏0
  • vue-router 一些容易被忽略的知識(shí)點(diǎn)

    摘要:調(diào)用全局的守衛(wèi)。在被激活的組件里調(diào)用。用創(chuàng)建好的實(shí)例調(diào)用守衛(wèi)中傳給的回調(diào)函數(shù)。 本文適用于對(duì) Vue.js 和 vue-router 有一定程度了解的開發(fā)者除特殊說(shuō)明,vue-router 版本為 3.0.2 正文 路由 class 匹配 路由匹配后會(huì)給該標(biāo)簽添加 class 屬性值 .router-link-active,該功能在嵌套路由中十分方便 class 的實(shí)際屬性值可以通...

    chunquedong 評(píng)論0 收藏0
  • Vue中的驗(yàn)證登錄狀態(tài)

    摘要:用存儲(chǔ)用戶路由守衛(wèi)路由中設(shè)置的字段就在當(dāng)中每次跳轉(zhuǎn)的路徑登錄狀態(tài)下訪問(wèn)頁(yè)面會(huì)跳到如果沒有訪問(wèn)任何頁(yè)面。一個(gè)簡(jiǎn)單的保存登錄狀態(tài)的小。 Vue項(xiàng)目中實(shí)現(xiàn)用戶登錄及token驗(yàn)證 先說(shuō)一下我的實(shí)現(xiàn)步驟: 使用easy-mock新建登錄接口,模擬用戶數(shù)據(jù) 使用axios請(qǐng)求登錄接口,匹配賬號(hào)和密碼 賬號(hào)密碼驗(yàn)證后, 拿到token,將token存儲(chǔ)到sessionStorage中,并跳轉(zhuǎn)到首...

    draveness 評(píng)論0 收藏0
  • 19/3/31學(xué)習(xí)筆記

    摘要:在失活的組件里調(diào)用離開守衛(wèi)。調(diào)用全局的守衛(wèi)。用創(chuàng)建好的實(shí)例調(diào)用守衛(wèi)中傳給的回調(diào)函數(shù)。路由元信息定義路由的時(shí)候可以配置字段 vue-router1 router-link 導(dǎo)航到不同組件 Go to Foo Go to Bar 定義路由const routes = [ { path: /foo, component: Foo }, { path: /bar, component: B...

    UnixAgain 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<