首页 > 编程 > JavaScript > 正文

vue-router源码之history类的浅析

2019-11-19 11:30:36
字体:
来源:转载
供稿:网友

当前版本: 3.0.3

类目录: src/history/base.js

前言:

对于vue-router来说,有三种路由模式history,hash,abstract, abstract是运行在没有window的环境下的,这三种模式都是继承于history类,history实现了一些共用的方法,对于一开始看vue-router源码来说,可以从这里开始看起。

初始属性

router: Router; 表示VueRouter实例。实例化History类时的第一个参数 base: string;  表示基路径。会用normalizeBase进行规范化。实例化History类时的第二个参数。 current: Route; 表示当前路由(route)。 pending: ?Route; 描述阻塞状态。 cb: (r: Route) => void; 监听时的回调函数。 ready: boolean; 描述就绪状态。 readyCbs: Array<Function>; 就绪状态的回调数组。 readyErrorCbs: Array<Function>; 就绪时产生错误的回调数组。 errorCbs: Array<Function>; 错误的回调数组 // implemented by sub-classes <!-- 下面几个是需要子类实现的方法,这里就先不说了,之后写其他类实现的时候分析 --> +go: (n: number) => void; +push: (loc: RawLocation) => void; +replace: (loc: RawLocation) => void; +ensureURL: (push?: boolean) => void; +getCurrentLocation: () => string;

对于history类来说,主要是下下面两个函数的逻辑

transitionTo

这个方法主要是对路由跳转的封装, location接收的是HTML5History,HashHistory,AbstractHistory, onComplete是成功的回调,onAbort是失败的回调

transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {  const route = this.router.match(location, this.current) // 解析成每一个location需要的route  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) })   }  }) }

confirmTransition

这是方法是确认跳转,route是匹配的路由对象, onComplete是匹配成功的回调, 是匹配失败的回调

confirmTransition(route: Route, onComplete: Function, onAbort?: Function) {    const current = this.current    const abort = err => { // 异常处理函数      if (isError(err)) {        if (this.errorCbs.length) {          this.errorCbs.forEach(cb => { cb(err) })        } else {          warn(false, 'uncaught error during route navigation:')          console.error(err)        }      }      onAbort && onAbort(err)    }    if (      isSameRoute(route, current) &&      // in the case the route map has been dynamically appended to      route.matched.length === current.matched.length    ) {      this.ensureURL()      return abort()    }    <!-- 根据当前路由对象和匹配的路由:返回更新的路由、激活的路由、停用的路由 -->    const {      updated,      deactivated,      activated    } = resolveQueue(this.current.matched, route.matched)    <!-- 需要执行的任务队列 -->    const queue: Array<?NavigationGuard> = [].concat(      // beforeRouteLeave 钩子函数      extractLeaveGuards(deactivated),      // 全局的beforeHooks勾子      this.router.beforeHooks,      // beforeRouteUpdate 钩子函数调用      extractUpdateHooks(updated),      // config里的勾子      activated.map(m => m.beforeEnter),      // async components      resolveAsyncComponents(activated)    )        this.pending = route    <!-- 对于queue数组所执行的迭代器方法 -->    const iterator = (hook: NavigationGuard, next) => {      if (this.pending !== route) {        return abort()      }      try {        hook(route, current, (to: any) => {          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)      }    }        runQueue(queue, iterator, () => {      const postEnterCbs = []      const isValid = () => this.current === route      <!-- beforeRouteEnter 钩子函数调用 -->      const enterGuards = extractEnterGuards(activated, postEnterCbs, isValid)      const queue = enterGuards.concat(this.router.resolveHooks)      <!-- 迭代运行queue -->      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() })          })        }      })    })  }

结语:

每一次总结,都是对之前读源码的再一次深入的了解

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表