Heim  >  Artikel  >  Web-Frontend  >  Führt Sie durch den Navigationsschutz von vue-Router

Führt Sie durch den Navigationsschutz von vue-Router

不言
不言nach vorne
2018-09-30 15:58:343936Durchsuche

Der Inhalt dieses Artikels führt Sie durch den Navigationsschutz von vue-Router. Er hat einen gewissen Referenzwert. Ich hoffe, er wird Ihnen hilfreich sein.

Vue-Router-Navigationswächter

In diesem Artikel werde ich die folgenden Dinge für Sie klären:

1: Wie ist die Ausführungsreihenfolge von Navigationswächtern?

2: Welchen Nutzen hat Next im Navigationsschutz?

3: Warum hat der AfterEach-Guard nicht „next“?

4: Kann beforeEach überlagert werden?

5: Durch welche Teile geht der Routing-Sprung?

Wie bereits erwähnt, hilft uns das Verlaufsattribut einer Content-Router-Instanz bei der Ausführung aller Sprungteile, sodass der Inhalt des Navigationsschutzes auch im Verlauf enthalten ist.

Führt Sie durch den Navigationsschutz von vue-Router

Schauen wir uns diese Push-Methode mit der HTML5History-Klasse an:

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 ($router when we jump. push ist diese Methode), transitTo wird aufgerufen, um eine Reihe von Sprunginhalten abzuschließen, aber diese Methode ist in der HTML5-Klasse nicht vorhanden. Die von der base.js-Klasse geerbte Methode dient der Implementierung von Routensprüngen Die Methode
transitionTo ist eine Kombination aus der secureTranstion-Methode und der uodateRoute-Methode, übersetzt ins Mandarin: Der Routensprung muss zuerst einen Bestätigungssprungprozess durchlaufen und dann nach Abschluss des Bestätigungsprozesses einen Routenaktualisierungsvorgang durchführen,

transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {
    // 获取要跳转的并且经过处理的路由
    const route = this.router.match(location, this.current)
    // confirmTranstion确认跳转过程
    this.confirmTransition(route, () => {
      // 确认完毕后完成更新路由操作
      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) })
      }
    })
  }
Was macht „confirmTransiton“? Überprüfen Sie zunächst, ob Sie sich auf der gleichen Route befinden. Wenn ja, dann tun wir nichts. Im zweiten Schritt beginnen wir mit dem Sammeln einer Welle von Wachen, sammeln dann die Wachen und führen dann jeden Wachen einmal aus. Die Bestätigungstransition wird erfolgreich ausgeführt.

Im Folgenden einige Screenshots des Quellcodes:

Führt Sie durch den Navigationsschutz von vue-Router

Was sind die Schwierigkeiten bei diesem Prozess?

Wie sammelt man Wachen, um eine Wachschlange zu bilden?

Wie kann man Wachen nacheinander ausführen und gleichzeitig die Wachwarteschlange jederzeit abbrechen?

So finden Sie den Knoten, nachdem die Guard-Warteschlange ausgeführt wurde (Sie können uns benachrichtigen, nachdem die Guard-Warteschlange ausgeführt wurde)

Eine runQueue-Funktion ist im Vue-Router gekapselt, um die oben genannten drei Probleme zu lösen . zwei. Die erste Frage betrifft ein großes Kapitel über das Routing der Vue-Router-Verarbeitung. Konzentrieren wir uns auf die runQueue-Funktion

Die Idee der runQueue-Funktion:

1: Iterator-Modus, um die Durchquerung sicherzustellen queue Jeder Schritt ist steuerbar.

2: Führen Sie die entsprechende Rückruffunktion aus, nachdem die Warteschlange abgeschlossen ist.

Leiten Sie die entsprechende Funktion aus den Funktionsparametern ab:

queue: muss ausgeführt werden Guard-Warteschlange

fn: Jeder Guard in der Guard-Warteschlange führt die Iteratorfunktion

fn aus nicht verwendet, geht nicht zum nächsten Schritt (sehr wichtig)

cb: Bei der am Ende aufgerufenen Rückruffunktion

export function runQueue (queue: Array<?NavigationGuard>, fn: Function, cb: Function) {
  const step = index => {
  // 队列里已经没有内容可以执行了,那就代表队列执行完成了
    if (index >= queue.length) {
      cb()
    } else {
      // 如果队列内容存在就执行迭代函数
      if (queue[index]) {
        fn(queue[index], () => {
          step(index + 1)
        })
      // 什么也没有那就到下一步了        
      } else {
        step(index + 1)
      }
    }
  }
  // 启动了
  step(0)
}
runQueue geht es darum, wie wir uns bei der Lösung des Problems der Schutzwarteschlange helfen können Verarbeitung.

(Beeilen Sie sich, diese Funktion ist großartig!)

Wir haben den großen Hammer für die Handhabung der Wachwarteschlange entwickelt und können mit der Arbeit daran beginnen. ?

Ja, ja, es gibt immer noch eine Schlange von Wachen, die eingesammelt werden müssen.

Zu diesem Zeitpunkt müssen wir darüber nachdenken, welche Art von Wachen es gibt?

Es gibt zwei Arten von Schutzvorrichtungen: vordere Schutzvorrichtungen und hintere Schutzvorrichtungen.

  • Front Guard:

  1. Globaler Front Guard: beforeEach beforeResolve

  2. Guards exklusiv zum Routing: beforeEnter

  3. Guards innerhalb der Komponente: beforeRouterEnter, beforeRouterUpdate, beforeRouteLeave

  • Post Guard:

    1. Globale Postwache: afterEach

    Wir müssen darüber nachdenken, wie diese Wachen registriert werden,

    • In der Routing-Instanz registriert:

      beforeEach, beforeResolve, afterEach

    • In der Routing-Konfiguration registriert (Route Exclusive Guard):

      beforeEnter

    • Route Guards innerhalb der Komponente:

      beforeRouteLeave, beforeRouteUpdate, beforeRouteEnter

    Okay, wir werden das entsprechende extrahieren Wachen. Die Wachen von

    confirmTransition sind in zwei Warteschlangen unterteilt: Schauen wir uns zunächst die erste Warteschlange an

     // 拿到路由跳转中更新、摧毁、激活时对应展示的组件。
     const {
          updated,
          deactivated,
          activated
        } = resolveQueue(this.current.matched, route.matched)
        // 路由守卫
        const queue: Array<?NavigationGuard> = [].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)
        )
    Die Reihenfolge einer Warteschlange:

    1. Diejenigen, die die zerstörten Komponenten erhalten, verdrängen alle verbleibenden Wachen in den Komponenten.

    2. Global vor jeder Komponente.

    3. Besorgen Sie sich alle aktualisierten Komponenten und entfernen Sie die Update-Guards in allen Komponenten.

    4. Durchqueren Sie die Routen, die Sie betreten möchten, und erhalten Sie die exklusiven Wächter aller Routen.

    5. Laden Sie die zu aktivierende asynchrone Komponente

    4 der 7 Wachen werden der Reihe nach herausgenommen und in die erste Warteschlange gestellt.

    Der nächste Schritt besteht darin, einen Iterator zu haben, der Wachen verwaltet:

    我们该如何处理守卫?

    1. 保证在守卫中可以停止并且跳转到其余路由,

    2. 保证守卫可以正常通过,

    const iterator = (hook: NavigationGuard, next) => {
          if (this.pending !== route) {
            return abort()
          }
          try {
            hook(route, current, (to: any) => {
              // 传个false就直接执行路由的错误处理,然后停止什么都不做。
              if (to === false || isError(to)) {
                // next(false) -> abort navigation, ensure current URL
                this.ensureURL(true)
                abort(to)
              } else if (
              // 如果我们接受了一个可以操作的路径。
                typeof to === 'string' ||
                (typeof to === 'object' && (
                  typeof to.path === 'string' ||
                  typeof to.name === 'string'
                ))
              ) {
                // next('/') or next({ path: '/' }) -> redirect
                abort()
                // 我们就执行路由跳转操作,并且守卫队列停止下面的迭代
                if (typeof to === 'object' && to.replace) {
                  this.replace(to)
                } else {
                  this.push(to)
                }
              } else {
                // confirm transition and pass on the value
                // 接续迭代下去咯
                next(to)
              }
            })
          } catch (e) {
            abort(e)
          }
        }

    next函数,之前在将runQueue的函数的时候,fn接收第二个参数(之前画过重点),第二个参数的回调函数是完成迭代器向下一步执行的功能。

    下面会有一点乱:

    所有的前置守卫都接收三个参数

    beforeEnter(to,from,next)=>{
        //这个next就是我们看到的 hook里面接收的箭头函数((to:any)=>{})
        //这个箭头函数里面对迭代器的next进行了一下掉用,
        //保证在一定情况下迭代器可以向下走一步。
        next('/index')
        // 我们在这种next('/index')传递一个可以执行的路径时,(to:any)=>{}
        //这个箭头函数并不会调用迭代的next,而是跳转别的路径执行了push操作。
        // 如果我们不掉用守卫中的next,迭代器的next肯定并不会执行,守卫的迭代就停止了,
        // 守卫堵塞confirmTransition并不会执行完毕,也就不会由后面的更细路由操作了。
    }
    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() })
              })
            }
          })
        })

    我们在把第一个queue(四个守卫与一个异步组件的加载)执行完毕后,要收集与执行第二个queue了,

    第二个queue:

    1. 收集了被的激活组件内的进入守卫

    2. 全局的beforeResolve的守卫

    收集完开始执行第二个queue的迭代。第二个queue执行完执行一下onComplete函数,代表着confirmTransition方法执行完毕了。确认路由的过程结束了,

    下面就是updateRoute的过程。updateRoute的时候执行全部的后置守卫,因为更新路由之后,当前的路由已经变化了,所以在给守卫传参数的时候缓存了一下,之前的路由。

    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呢?因为afterEach根本不在迭代器之内,他就没有next来触发迭代器的下一步。

    最后我们说一下beforeEach的内容:
    我们设置beforeEach全局守卫的时候,守卫们存储在哪里?

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

    这段代码beforeEach是通过注册守卫的方式,将注册的全局前置守卫放在beforeHooks的容器内,这个容器里面装载着所有的前置守卫

    Führt Sie durch den Navigationsschutz von vue-Router

    一家人(全局的 前置进入、前置resolve、后置守卫)整整齐齐的放在对应的容器里面,容器是个数组,所以注册全局守卫的时候,是支持注册多个的,

    router.beforeEach(()=>{xxx});
    router.beforeEach(()=>{yyy});
    // 这两个守卫都会执行,只是先注册的先执行,
    // registerHook这个方法还可以清除对应的守卫,这个方法也可以使用

    总结

    我们来回答一下开篇的5个问题

    1:导航守卫的执行顺序是怎么样的?

    beforeRouteLeave

    2:导航守卫中的next的用处?

    next的作用,使导航守卫队列的继续向下迭代

    3:为什么afterEach守卫没有next?

    afterEach根本不在导航守卫队列内,没有迭代的next

    4:beforeEach是否可以叠加?

    beforeEach是可以叠加的,所有的全局前置守卫按顺序存放在beforeHooks的数组里面,

    5:路由跳转经历了哪几部分?

    路由跳转的核心方法是transitionTo,在跳转过程中经历了一次confirmTransition,

    (beforeRouteLeave

    在第一个queue迭代完毕后,执行第二个(beforeRouteEnter

    在执行完毕后,开始执行updateRoute,之后执行全局的afterEach守卫。最后完成路由的跳转。

    5个问题解答完毕,希望对你的业务有帮助。


    Das obige ist der detaillierte Inhalt vonFührt Sie durch den Navigationsschutz von vue-Router. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Stellungnahme:
    Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen