前端路由探究(1) vue-router源码学习-基本数据结构

搭建实验环境

首先github download下来https://github.com/vuejs/vue-router vue-router最新的代码,代码在src下,结构清晰,但不适合调试看中间的一些处理结果,所以新建一个文件夹,新建index.html,创建好vue-router官网上的demo实例




    
    
    
    Document


    

Hello App!

Go to Foo Go to Bar

不同的是将官网上的CDN代码download下来到本地同文件夹下。
github下载的工程文件比较好阅读,单文件的vue-router.js可以一步步调试看数据结构,两个结合起来看。

matcher

我们打开VueRouter对象代码,有两个地方值得关注,一个是

this.matcher = createMatcher(options.routes || [], this);

另一个

  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:
      {
        assert(false, ("invalid mode: " + mode));
      }
  }

可以看出一个是初始化matcher的createMatcher,打开createMatcher方法


前端路由探究(1) vue-router源码学习-基本数据结构_第1张图片
createMatcher

我们的任务是看到vue-router是怎么处理存储路由结构的,所以应该是createRouteMap和addRoutes这个两个方法相关,但打开addRoutes,其实也是调用了createRouteMap,它是暴露给用户动态添加路由的方法。

so ,看createRouteMap,这个方法有个循环routes调用addRouteRecord,最终生成每个路由的数据结构


createRouteMap处理routers

追寻到这个方法,我们找到了每个routes的record数据结构


前端路由探究(1) vue-router源码学习-基本数据结构_第2张图片
record结构

其中regex是通过给出的路由生成对应的正则表达式,还有对应的components,addRouteRecord还考虑了子路由的处理过程。但最终record通过对象map放到pathMap
前端路由探究(1) vue-router源码学习-基本数据结构_第3张图片
pathMap

我们可以通过console打印出来


pathMap

而最终createRouteMap返回出来的是, 即VueRouter中matcher对象的数据结构。
前端路由探究(1) vue-router源码学习-基本数据结构_第4张图片
createRouteMap返回结构

History

可以看到VueRouter如下生成History

  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:
      {
        assert(false, ("invalid mode: " + mode));
      }
  }

分别是vue-router三种模式,具体的分别就不介绍了,官网上有。但这三个对象都是继承了基本的History类。在vue-router工程文件src/history/base.js,可以看到这个类的定义


前端路由探究(1) vue-router源码学习-基本数据结构_第5张图片
History

简单的来说,我们操作路由router.push({ path: 'home' }),其实是在操作这个对象上的方法,而各个模式下的具体操作不同,例如hash模式下需要监听popstate和hashchange事件,调用之前matcher的match函数(具体调用在History的transitionTo中),匹配并更新window.history。具体的操作都在src/history下。
主要关注setupListeners -> transitionTo -> pushState这个几个方法的处理。可以看到最终操作window.history的是history.replaceState和history.pushState两个游览器API。

总结

通过matcher和History两个最重要的对象,VueRouter就完成了将我们定义好的路由结构转换成可以匹配的路由对象,并且添加事件监听,完成对相应路由的匹配并更新url历史。那么还有一个最重要的就是最终操作匹配到的组件并更新,这个下次写, 还有View和Link两个组件,其实也很简单,调用了Vue.util.defineReactive,定义了一个响应式对象:

Vue.util.defineReactive(this, '_route', this._router.history.current)

你可能感兴趣的:(前端路由探究(1) vue-router源码学习-基本数据结构)