transitionTo ( location: RawLocation, onComplete?: Function, onAbort?: Function ) { let route try { route = this.router.match(location, this.current) } catch (e) { this.errorCbs.forEach(cb => { cb(e) }) throw e } const prev = this.current this.confirmTransition( route, () => { this.updateRoute(route) onComplete && onComplete(route) this.ensureURL() this.router.afterHooks.forEach(hook => { hook && hook(route, prev) })
if (!this.ready) { this.ready = true this.readyCbs.forEach(cb => { cb(route) }) } }, err => { if (onAbort) { onAbort(err) } if (err && !this.ready) { if (!isNavigationFailure(err, NavigationFailureType.redirected) || prev !== START) { this.ready = true this.readyErrorCbs.forEach(cb => { cb(err) }) } } } ) } confirmTransition (route: Route, onComplete: Function, onAbort?: Function) { const current = this.current this.pending = route const abort = err => { if (!isNavigationFailure(err) && isError(err)) { if (this.errorCbs.length) { this.errorCbs.forEach(cb => { cb(err) }) } else { if (process.env.NODE_ENV !== 'production') { warn(false, 'uncaught error during route navigation:') } console.error(err) } } onAbort && onAbort(err) } const lastRouteIndex = route.matched.length - 1 const lastCurrentIndex = current.matched.length - 1 if ( isSameRoute(route, current) && lastRouteIndex === lastCurrentIndex && route.matched[lastRouteIndex] === current.matched[lastCurrentIndex] ) { this.ensureURL() if (route.hash) { handleScroll(this.router, current, route, false) } return abort(createNavigationDuplicatedError(current, route)) } const { updated, deactivated, activated } = resolveQueue( this.current.matched, route.matched ) const queue: Array<?NavigationGuard> = [].concat( extractLeaveGuards(deactivated), this.router.beforeHooks, extractUpdateHooks(updated), activated.map(m => m.beforeEnter), resolveAsyncComponents(activated) ) const iterator = (hook: NavigationGuard, next) => { if (this.pending !== route) { return abort(createNavigationCancelledError(current, route)) } try { hook(route, current, (to: any) => { if (to === false) { this.ensureURL(true) abort(createNavigationAbortedError(current, route)) } else if (isError(to)) { this.ensureURL(true) abort(to) } else if ( typeof to === 'string' || (typeof to === 'object' && (typeof to.path === 'string' || typeof to.name === 'string')) ) { abort(createNavigationRedirectedError(current, route)) if (typeof to === 'object' && to.replace) { this.replace(to) } else { this.push(to) } } else { next(to) } }) } catch (e) { abort(e) } }
runQueue(queue, iterator, () => { const enterGuards = extractEnterGuards(activated) const queue = enterGuards.concat(this.router.resolveHooks) runQueue(queue, iterator, () => { if (this.pending !== route) { return abort(createNavigationCancelledError(current, route)) } this.pending = null onComplete(route) if (this.router.app) { this.router.app.$nextTick(() => { handleRouteEntered(route) }) } }) }) }
function extractEnterGuards ( activated: Array<RouteRecord> ): Array<?Function> { return extractGuards( activated, 'beforeRouteEnter', (guard, _, match, key) => { return bindEnterGuard(guard, match, key) } ) }
|