VueRouter源码解析(一):插件安装,几个类型,几个方法

691 阅读6分钟

       文章以图片中代码注释为主,文字只是描述大致思路。可能有些非常细节的地方没有分析,因为分析VueRouter源码主要还是为了研究为什么router-link,router-view与前端路由之间的关联。搞清楚VueRouter的工作方式。具体的细节问题在对整个VueRouter有了了解之后,可以再结合工作中的实际问题来处理。

插件注册

老生常谈的问题了,在Vuex分析的文章中,就有插件功能的分析(juejin.cn/user/208432…

Vue.use

cn.vuejs.org/v2/api/#Vue…

install

1. 为install函数添加静态属性installed,以此来防止插件多次安装

2. 调用Vue.mixin,全局混入beforeCreate与destoryed方法。

    2.1在beforeCreate方法中通过组件之间的父子关系,让根组件(app.vue)的后代们都可以访           问到根组件的VueRouter实例。

    2.2 调用VueRouter实例的init方法。

    2.2 利用Vue.util.defineReactive方法向根组件添加_route属性,其值为Vue应用当前的路              由地址,如此一来根据【当前路由地址】的变化来驱动视图改变。

3.  在Vue的原型链上添加router属性与router属性与route属性,两个属性都为【只读】属性。其中router的值为VueRouter实例,router的值为VueRouter实例,route当前路由地址。

4. 注册RouterView,RouterLink组件

5. beforeRouter/beforeRouteLeave/beforeRouterUpdate的合并策略与created的合并策略一致。

this._router.init(this)

VueRouter自带对滚动轴的控制功能,init主要做的事情是:1)对scroll事件进行监听;2)可以向多个组件传入router,但是要保证不会重复监听scorll事件。

new VueRouter

直接看构造函数吧,最主要是是createMatcher方法与history实例。

1. VueRouter路由模式一般来说是由两种hash模式与html5模式,当然,这个是在浏览器端。在非浏览器环境下还有abstract模式。

2. createMatcher方法。返回addRouters与matcher方法。这两个是VueRouter最核心的方法。

createMatcher

在分析createMatcher方法之前,先给几个基本信息。有了这些信息会更好地了解VueRouter是如何工作的。

Vue全家桶的开发都用了Facebook的flow,下面就来看几个类型。

在我分析VueRouter源码的时候有写地方看着很迷糊,又是record又是location的。最后我发现这些都是有不同用处的。而类型也都在flow内声明了。

这里最值得注意的是RouteRecord类型(对应源码中的变量为record)含有components属性,其值肯定是Vue组件。

Route类型(对应源码中的变量为route)含有matched属性,其值为一连串具有父子关系的record组成的数组。

RawLocation(对应源码中的变量为raw)是字符串或者Route类型,为路由跳转的目的地。

现在正式分析createMatcher方法

1. 将用户自定义的路由传入createRouteMap函数得到,所有自定义路由path组成的数组pathList;path为key,route为值组成的pathMap;name为key,route为值组成的nameMap

2. 定义 addRoutes方法,其核心就是调用createRouteMap方法(传入旧的pathList,pathMap,nameMap)。

3. 定义 match方法

1. createRouteMap 与 addRouteRecord

1. createRouteMap会遍历用户自定义路由数组调用addRouteRecord方法。

2. 用户可以传入通配符*,保证*出现在路径数组pathList的最后

addRouteRecord

1. 标准化用户自定义路径

2. 定义record对象,其含有components对象,一般我们都会在自定义路由内使用component而非components,如果写了component,会被转换为coomponents,其key为default,value为用户引入的组件

3. 如果自定义路由有children属性就遍历子元素递归调用addRouteRecord函数

4. pathMap对象,pathList数组添加元素(同样的key不会被二次加入)

5. 如果自定义了alias的值,那么就把用户自定义的alias当成path,再执行一遍addRouteRecord函数

6. 如果用户自定义了name的值,就往nameMap属性内添加元素(相同的name不会被二次加入,如果非生产环境下,会提示重复添加相同名称的路由,这里只是提示,其实根本不用处理,因为在官方issure下看见有人提了,所以特地看了一下这方面的源码,其实只要开发中保证每一个路由地址都有独一无二的name值,就不会出现问题。issure地址:)

7. 函数是没有返回值的,因为传入的pathList,pathMap,nameMap都是引用对象

2.  addRoutes

pathList,pathMap,nameMap为引用对象,其值为初次创建路由时会产生的。

用词方法我们可以动态添加路由,动态添加路由的时候会出现重复添加名称相同路由的问题,第一部分已经详细说过,不再赘述。 

3. match

match方法有三个参数,分别是要跳转到路径,现在的路径,重定向参数

1. normalizeLocation根据跳转路径与现在路径获取标准化的目标路径,其为Location类型

2. 如果要跳转的标准化路径对象有name属性就直接获取name对应的record并创建route类型的对象返回

3. 没有name属性就获取path对应的record并创建爱你route类型的对象返回

4. 如果既没有name也没有path就返回一个空的route类型对象

注:跳转的时候可以传入name属性,name优先级高于path/alias

4. _createRoute与createRoute

上小节提到根据record常见route类型的对象,正是利用了_createRoute函数。

redirect与alias就先略过了,重点 看createRoute方法

createRoute方法中最需要关注的route的matched属性,如果有match函数执行后匹配到的record对象,那么就会调用formatMatch函数返回值并赋给matched属性。

5. formarMatch

其实formatMatch很简单,在用户定义的routes对象内都有父子关系,record之间也会建立斧子关系,那么route类型的matched属性的值就是一个record类型组成的数组,数组index从0是祖先,最后一个是匹配到的record。

这个伏笔在RouterView组件会再次出现。

最后

文章大概会分3-4个篇。

这篇先介绍了一个组件的安装与初始化。介绍了Location,record,raw,route的类型,为后续的分析打下基础。

随后分析了addRoutes与match方法。知道了addRoutes其实就是往pathList,pathMap,nameMap对象添加用户自定义路由;match就是根据传入的目标路由与现在的路径获取route对象,其中牵扯到了location,record,raw,route几个类型的值,在有前面的类型介绍之后会容易理解很多。

下篇文章会分析一下history类。