vue-Router의 내비게이션 가드를 안내해 드립니다.

不言
풀어 주다: 2018-09-30 15:58:34
앞으로
3907명이 탐색했습니다.

이 글의 내용은 vue-Router의 내비게이션 가드를 안내하는 내용입니다. 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.

vue-router 네비게이션 가드

이 기사에서는 다음 사항을 정리하겠습니다.

1: 네비게이션 순서는 무엇입니까 어떤 경비원이 처형됩니까?

2: 네비게이션 가드에서 next의 용도는 무엇인가요?

3: AfterEach Guard에는 왜 다음이 없나요?

4: beforeEach를 중첩할 수 있나요?

5: 라우팅 점프는 어떤 부분을 거치나요?

앞서 언급했듯이 콘텐츠 라우터 인스턴스의 기록 속성은 모든 점프 부분을 수행하는 데 도움이 되므로 탐색 가드의 콘텐츠도 기록에 포함됩니다.

vue-Router의 내비게이션 가드를 안내해 드립니다.

HTML5History 클래스를 사용하여 이 푸시 메서드를 살펴보겠습니다.

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.push가 이 메서드입니다.) 프로세스 중에 일련의 점프 콘텐츠를 완료하기 위해 TransitionTo가 호출되지만 이 메서드는 HTML5 클래스에는 존재하지 않으며 base.js 클래스의 메서드에서 상속됩니다. # 🎜🎜#transitionTo는 경로 점프를 구현하는 방법입니다
transitionTo의 주요 프로세스는 verifyTranstion 메서드와 uodateRoute 메서드를 중국어로 번역하면: 경로 점프는 확인 프로세스 중에 먼저 확인 점프 프로세스를 거쳐야 합니다. 완료 후 라우팅 업데이트 작업을 수행합니다.

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) })
      }
    })
  }
로그인 후 복사
confirmTransiton은 무엇을 했나요? 먼저 동일한 경로에 있는지 확인하십시오. 그렇다면 아무것도 하지 마십시오. 두 번째 단계에서는 가드 수집을 시작한 다음 가드를 수집하고 각 가드를 한 번 실행해야 합니다. 확인 전환이 성공적으로 실행됩니다.

다음은 소스 코드의 일부 스크린샷입니다.

vue-Router의 내비게이션 가드를 안내해 드립니다.

어려움은 무엇인가요? 이 과정에서?

경비대를 모아 가드 대기열을 구성하는 방법은 무엇인가요?

언제든지 가드 큐를 중단하면서 가드를 순차적으로 실행하는 방법은 무엇입니까?

가드 큐 실행 후 노드를 찾는 방법(가드 큐 실행 후 알려주시면 됩니다)

runQueue 함수를 vue-router에 캡슐화하여 해결합니다. 위의 세 가지 문제 마지막 두 가지 질문입니다. 첫 번째 질문은 vue-router 처리 라우팅의 큰 장과 관련됩니다. runQueue 함수에 초점을 맞추겠습니다.

runQueue 함수의 아이디어:

1: Iterator 모드 큐를 순회할 때 모든 단계를 제어할 수 있도록 하기 위해

2: 큐가 완료된 후 해당 콜백 함수를 실행합니다.

함수 매개변수의 해당 함수를 추론합니다. : #🎜 🎜#

queue: 실행되어야 하는 가드 큐

fn : 반복자 함수, 가드 큐의 각 가드가 반복자 함수를 실행

fn 두 매개변수는 반복자가 다음 단계로 진입하도록 만듭니다. 사용하지 않으면 다음 단계로 진입하지 않습니다. (매우 중요)

cb : 마지막에 호출되는 콜백 함수

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는 가드 큐 처리 문제를 해결하는 데 도움이 되는 방법이면 충분합니다.

(서두르세요, 이 기능은 굉장합니다!)

가드 큐를 처리하는 큰 망치를 만들었고, 그러면 가드 큐가 작업을 시작할 준비가 되었습니다. 모직물? ?

예, 예, 아직 수집해야 할 경비원 대기열이 있습니다.

이때 우리는 어떤 경비원들이 있는지 생각해 보아야 할까요?


가드에는 프론트가드와 리어가드 두 종류가 있습니다.

    프런트 가드:
    글로벌 프론트 가드: beforeEach beforeResolve#🎜 🎜## 🎜🎜#
  1. 경로 전용 가드: beforeEnter

  2. 구성 요소 내의 가드: beforeRouterEnter, beforeRouterUpdate, beforeRouteLeave#🎜🎜 ##🎜🎜 #

  3. 포스트 가드:

  • 글로벌 포스트 가드: afterEach#🎜 🎜#

    # 🎜🎜#

  • 이 경비원이 어떻게 등록되는지 생각해야 합니다.
    1. 다음 라우팅 인스턴스에 등록:
    2. # 🎜🎜#beforeEach, beforeResolve, afterEach

    라우팅 구성에 등록됨(경로 전용 가드):
      #🎜 🎜#beforeEnter
    • #🎜 🎜#

      구성 요소 내의 경로 가드:

      beforeRouteLeave, beforeRouteUpdate, beforeRouteEnter
    • 좋아, 간다

      confirmTransition의 가드는 두 개의 큐로 나뉩니다. 먼저 첫 번째 큐를 살펴보겠습니다.
     // 拿到路由跳转中更新、摧毁、激活时对应展示的组件。
     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)
        )
    로그인 후 복사
  • One 큐의 순서: #🎜🎜 #

    파손된 부품을 얻으면 부품에 남아있는 가드를 모두 짜내세요.

  • 각 구성 요소 이전에 전역입니다.

    업데이트된 모든 구성 요소를 가져오고 모든 구성 요소에서 업데이트 가드를 짜내세요.

    1. 들어가고 싶은 경로를 횡단하고 모든 경로의 전용 가드를 획득하세요.

    2. 활성화할 비동기 컴포넌트 로드 중

    3. 가드 7명 중 4명이 활성화 중입니다. 꺼내세요 순서대로 첫 번째 대기열에 넣습니다.

    4. 다음 단계는 가드를 처리하는 반복자를 갖는 것입니다.
    5. 我们该如何处理守卫?

      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的容器内,这个容器里面装载着所有的前置守卫

      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个问题解答完毕,希望对你的业务有帮助。


    위 내용은 vue-Router의 내비게이션 가드를 안내해 드립니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    관련 라벨:
    원천:segmentfault.com
    본 웹사이트의 성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
    최신 이슈
    인기 튜토리얼
    더>
    최신 다운로드
    더>
    웹 효과
    웹사이트 소스 코드
    웹사이트 자료
    프론트엔드 템플릿
    회사 소개 부인 성명 Sitemap
    PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!