学习vue-router源码记录-1

因为本人开发中使用的是VUE技术栈,最近也是开始源码的学习,以此记录个人理解,若行文有误,请多多指教。

1.new Router和install

在vue中我们使用vue-router时需要先进行new Router(),执行new Router()后主要执行代码看看VueRouter class定义的constructor方法。

constructor (options: RouterOptions = {}) {
    this.app = null
    this.apps = []
    this.options = options
    this.beforeHooks = []
    this.resolveHooks = []
    this.afterHooks = []
    this.matcher = createMatcher(options.routes || [], this)

    let mode = options.mode || 'hash'
    this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false
    if (this.fallback) {
      mode = 'hash'
    }
    if (!inBrowser) {
      mode = 'abstract'
    }
    this.mode = mode

    switch (mode) {
      case 'history':
        this.history = new HTML5History(this, options.base)
        break
      case 'hash':
        this.history = new HashHistory(this, options.base, this.fallback)
        break
      case 'abstract':
        this.history = new AbstractHistory(this, options.base)
        break
      default:
        if (process.env.NODE_ENV !== 'production') {
          assert(false, `invalid mode: ${mode}`)
        }
    }
  }
复制代码

从代码里面我们可以看到在new的时候确定了使用何种路由模式,并且根据传入options创建matcher

接下来看看当使用vue.use()执行install方法做了什么:

export function install (Vue) {
  if (install.installed && _Vue === Vue) return
  install.installed = true

  _Vue = Vue

  const isDef = v => v !== undefined

  const registerInstance = (vm, callVal) => {
    let i = vm.$options._parentVnode
    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
      i(vm, callVal)
    }
  }

  Vue.mixin({
    beforeCreate () {
      if (isDef(this.$options.router)) {
        this._routerRoot = this
        this._router = this.$options.router
        this._router.init(this)
        Vue.util.defineReactive(this, '_route', this._router.history.current)
      } else {
        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
      }
      registerInstance(this, this)
    },
    destroyed () {
      registerInstance(this)
    }
  })

  Object.defineProperty(Vue.prototype, '$router', {
    get () { return this._routerRoot._router }
  })

  Object.defineProperty(Vue.prototype, '$route', {
    get () { return this._routerRoot._route }
  })

  Vue.component('RouterView', View)
  Vue.component('RouterLink', Link)

  const strats = Vue.config.optionMergeStrategies
  // use the same hook merging strategy for route hooks
  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}
复制代码

install方法里主要是Vue.mixin给每个组件混入了beforeCreatedestroyed 方法,在Vue的原型链上增加了$router$route对象,这就是为什么我们使用Vue的时候在this上可以拿到这两个对象,注册了router-viewrouter-link两个组件。

2. matcher和route

接下来看看matcher的定义:

export type Matcher = {
  match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route;
  addRoutes: (routes: Array<RouteConfig>) => void;
};
复制代码

matcher暴露了match方法addRoutes方法,从方法的名字上看,match方法是用于路由匹配,addRoutes则是用来添加路由配置。

在执行creatMatcher()里第一代段代码生成了pathListpathMapnameMap这三个对象,这是后面路由执行匹配非常重要的配置。

  const { pathList, pathMap, nameMap } = createRouteMap(routes)
复制代码

pathMapnameMap分别是以route配置的path和name为key生成的一个映射表,对应value为RouteRecord实例。

下面看看RouteRecord的定义:

declare type RouteRecord = {
  path: string;
  regex: RouteRegExp;
  components: Dictionary<any>;
  instances: Dictionary<any>;
  name: ?string;
  parent: ?RouteRecord;
  redirect: ?RedirectOption;
  matchAs: ?string;
  beforeEnter: ?NavigationGuard;
  meta: any;
  props: boolean | Object | Function | Dictionary<boolean | Object | Function>;
}
复制代码

结合代码里的实际数据对照理解各个属性的含义:

keyvalue
path传入的路径值
regex根据path生成的正则匹配规则
componentspath对应的组件
instances执行路由守卫方法时传入的route实例
nameroute的name
parentroute的父级,是一个递归的对象,从最底层一直到最顶层,无则为undefined
redirect重定向的路径
matchAs用于匹配alias
props传入路由的参数

结合以上解释,我们可以得出vue-router一个大概的运行概念。

  1. 执行new Router()生成路由配置对象routedRecord

  2. 路由匹配根据route对象的regex进行匹配

  3. 根据routeparent对象递归获取component组件生成render Tree

  4. 执行各组件对应的导航守卫方法

此文大概简述了vue-router是如何执行的,但是对于router跳转的具体执行并没有进行深入解释,下一篇文章将会详细说明router跳转之后是如何执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值