이 글의 내용은 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) }) } }) }
어려움은 무엇인가요? 이 과정에서? 경비대를 모아 가드 대기열을 구성하는 방법은 무엇인가요? 언제든지 가드 큐를 중단하면서 가드를 순차적으로 실행하는 방법은 무엇입니까? 가드 큐 실행 후 노드를 찾는 방법(가드 큐 실행 후 알려주시면 됩니다) runQueue 함수를 vue-router에 캡슐화하여 해결합니다. 위의 세 가지 문제 마지막 두 가지 질문입니다. 첫 번째 질문은 vue-router 처리 라우팅의 큰 장과 관련됩니다. runQueue 함수에 초점을 맞추겠습니다. runQueue 함수의 아이디어: 1: Iterator 모드 큐를 순회할 때 모든 단계를 제어할 수 있도록 하기 위해 2: 큐가 완료된 후 해당 콜백 함수를 실행합니다. 함수 매개변수의 해당 함수를 추론합니다. : #🎜 🎜#
queue: 실행되어야 하는 가드 큐
fn : 반복자 함수, 가드 큐의 각 가드가 반복자 함수를 실행
fn 두 매개변수는 반복자가 다음 단계로 진입하도록 만듭니다. 사용하지 않으면 다음 단계로 진입하지 않습니다. (매우 중요)
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는 가드 큐 처리 문제를 해결하는 데 도움이 되는 방법이면 충분합니다.
(서두르세요, 이 기능은 굉장합니다!)
예, 예, 아직 수집해야 할 경비원 대기열이 있습니다.
이때 우리는 어떤 경비원들이 있는지 생각해 보아야 할까요?
가드에는 프론트가드와 리어가드 두 종류가 있습니다.
경로 전용 가드: beforeEnter
구성 요소 내의 가드: beforeRouterEnter, beforeRouterUpdate, beforeRouteLeave#🎜🎜 ##🎜🎜 #
# 🎜🎜#
좋아, 간다 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) )
파손된 부품을 얻으면 부품에 남아있는 가드를 모두 짜내세요.
각 구성 요소 이전에 전역입니다.
업데이트된 모든 구성 요소를 가져오고 모든 구성 요소에서 업데이트 가드를 짜내세요.
들어가고 싶은 경로를 횡단하고 모든 경로의 전용 가드를 획득하세요.
활성화할 비동기 컴포넌트 로드 중
가드 7명 중 4명이 활성화 중입니다. 꺼내세요 순서대로 첫 번째 대기열에 넣습니다.
保证在守卫中可以停止并且跳转到其余路由,
保证守卫可以正常通过,
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:
收集了被的激活组件内的进入守卫
全局的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的容器内,这个容器里面装载着所有的前置守卫
一家人(全局的 前置进入、前置resolve、后置守卫)整整齐齐的放在对应的容器里面,容器是个数组,所以注册全局守卫的时候,是支持注册多个的,
router.beforeEach(()=>{xxx}); router.beforeEach(()=>{yyy}); // 这两个守卫都会执行,只是先注册的先执行, // registerHook这个方法还可以清除对应的守卫,这个方法也可以使用
我们来回答一下开篇的5个问题
beforeRouteLeave
next的作用,使导航守卫队列的继续向下迭代
afterEach根本不在导航守卫队列内,没有迭代的next
beforeEach是可以叠加的,所有的全局前置守卫按顺序存放在beforeHooks的数组里面,
路由跳转的核心方法是transitionTo,在跳转过程中经历了一次confirmTransition,
(beforeRouteLeave
在第一个queue迭代完毕后,执行第二个(beforeRouteEnter
在执行完毕后,开始执行updateRoute,之后执行全局的afterEach守卫。最后完成路由的跳转。
위 내용은 vue-Router의 내비게이션 가드를 안내해 드립니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!