vue-router源码随笔

插件执行入口:

if (inBrowser && window.Vue) {
  window.Vue.use(VueRouter) // 传递给use的一个对象,这个对象必须实现install方法。  VueRouter.install = install
}

在Vue.use中代码:plugin.install.apply(plugin, args),在VueRouter上下文中执行install方法。args为Vue对象,不是new的对象实例哦,它也就是VueRouter.install方法中的参数。

插件给vue对象实例暴露了两个属性:

  Object.defineProperty(Vue.prototype, '$router', {
    get () { return this._routerRoot._router }
  }) 
  // this._routerRoot在beforeCreate中定义。
  Object.defineProperty(Vue.prototype, '$route', {
    get () { return this._routerRoot._route }
  })

在new Vue的时候,先要new Router, 执行VueRouter的构造函数。实例很重要成员为matcher,它是一个对象,包括match和addRoutes两个方法,同时闭包了{pathList, pathMap, nameMap},它是把router对象转换为另外一种格式,很关键,看下三个属性的数据结构。

//pathList
["/foo","bar"]
//pathMap
"/bar":
{
  beforeEnter: undefined,  //在路由配置里调用 beforeEnter导航守护函数。
  components: {            //路径下对应的组件,可能有多个组件,
      default:
    {template: "<div>bar</div>"}
  },
  // 组件实例,初始的时候没有,在beforeCreate钩子函数registerInstance(this, this)赋值的,它调用
  // view组件中的data.registerRouteInstance,初始的时候不会调用,也就是instance为{}
  instances: {},          
  matchAs: undefined // alias用到
  meta: undefined, 
  name: undefined,
  parent: undefined,
  path: "/bar",
  // route.props == null? {}: route.components? route.props: { default: route.props }
  props: {},
  redirect: undefined
  regex: /^\/bar(?:\/(?=$))?$/i
}
//nameMap
nameMap:{
  'name':{   // name为path设置的名字
     //path对应的pathMap的对象
  }
}

接下来执行this.history = new HashHistory(this, options.base, this.fallback),调用base.js的构造函数和HashHistory的构造函数。其中this为router实例:结构如下:

/*结构如下:
{"app":null,
 "apps":[],
 "options":{
// 配置的路由信息 "routes":[ {"path":"/foo", "component": {"template":"<div>foo</div>"} }, { "path":"/bar", "component":{ "template":"<div>bar</div>"} } ] },
// 守护导航钩子函数 "beforeHooks":[], "resolveHooks":[], "afterHooks":[], "matcher":{}, "fallback":false, "mode":"hash" }
*/

执行base.js的构造函数之后添加了几个属性:

this.base = normalizeBase(base)
// start with a route object that stands for "nowhere"
this.current = START
this.pending = null
this.ready = false
this.readyCbs = []
this.readyErrorCbs = []
this.errorCbs = []
this.listeners = []

START初始为createRoute(null, {path:'/'}),返回一个不可改变的对象,这个对象就是对路径的解析完毕之后保存的路径的各个部分。

router对象结构如下:
{
  path:'\',
  param:'',
  query:'',
  hash:'',
  fullPath:'',
  name:'',
  raw:'',
  match:''
}

接下来执行checkFallback,初始时base为空字符,checkFallback它把当前的href转为为/#/,最后执行ensureSlash。getHash初始返回为'/',最终VueRouter.beforeCreate钩子函数执行完毕。

function getHash () {
  // We can't use window.location.hash here because it's not
  // consistent across browsers - Firefox will pre-decode it!
  // let href = window.location.href 
  // 对第一个#之后的字符串解码。
  let href = "http://www.baidu.com/#sh%20#s?sh#d%20sa"
  const index = href.indexOf('#')
  // empty path
  if (index < 0) return ''

  href = href.slice(index + 1)
  // decode the hash but not the search or hash
  // as search(query) is already decoded
  // https://github.com/vuejs/vue-router/issues/2708
  const searchIndex = href.indexOf('?')
  /*
     第一个#之后如果还有#或者还有?不需要解码
  */
  if (searchIndex < 0) {
    const hashIndex = href.indexOf('#')
    if (hashIndex > -1) {
      href = decodeURI(href.slice(0, hashIndex)) + href.slice(hashIndex)
    } else href = decodeURI(href)
  } else {
    href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex)
  }

  return href
}

 

posted @ 2020-06-03 11:06  anthonyliu  阅读(199)  评论(0编辑  收藏  举报