理解vue-router中的matcher
在vue-router中每个定义好的路由都会被解析成一个对应的matcher类型(routeRecordMatcher),路由的增删改查都会通过matcher实现.
在createRouter中会通过createRouterMatcher创建一个matcher(RouterMatcher类型)createRouterMatcher接收两个参数:routes、globalOptions.其中routes是我们定义的路由标,就是再createRouter时传入的options.routes,而globalOptions计师createRouter中的options。
globalOptions就是createRouter中的options.createRouterMatcher中声明了两个变量、matchers、matcherMap,用来存储通过路由表解析的matcher,该对象有addRouter、resolve、removeRoute、getRoute、getRecordMatcher几个属性,这几个属性都对应一个函数。
addRoute函数:它接收三个参数:record(新增路由)、parent(父matcher)、originalRecord(原始matcher)
addRoute中,会对record进行标准化处理(normalizeRouteRecord),如果存在原始的matcher,也就是originalRecord,说明此时要添加的路由是
另一记录的别名,这时会将originalRecord.record存入mainNormalizedRecord.aliasOf中。
然后会遍历record的别名,向normalizedRecords中添加由别名产生的路由,紧接着会遍历normalizeRecords:在这个遍历过程中,会首先将
path处理成完整的path,然后通过createRouteRecordMatchher方法创建一个matcher(routeRecordMatcher类型),
如果matcher是由别名产生的,那么matcher会被加入由原始记录产生的matcher中的alias属性中。然后会遍历mainNormalizedRecord的children属性
,递归调用addRoute方法,在最后,电泳insertMatcher添加新创建的matcher。
最后,addRoute会返回一个删除原始matcher的方法。
在addRoute的过程中,会调用createRouteRecordMatcher方法来创建matcher,那么matcher究竟是什么?它是如何被创建的?那就需要了解createRouteRecordMatcher的实现。那么这个函数前,我们需要了解tokenizePath、tokensToParser着两个函数,因为着量
是创建matcher的核心。tokenizePath的作用是将path转为一个token数组。而tokensToParser会根据token数组创建要给路径解析器。这里还有一个token的概念
vue-router中对token的定义由三种
分别为TokenStatic:静态token,说明token不可变
TokenParam:参数token,说明token是个参数
TokenGroup:分组token,下面对分组token进行举例说明
1.路由a/b/c
的token数组
[ [{type:TokenType.Static,value:'a}], [{type:TokenType.Static,value:'b'}], [{type:TokenType.Static,value:'b'}], ]
动态路由参数 /user/:id对应的token则是
[ [ { type: TokenType.Static, value: 'user',/:id(\\d+)new对应的token数组: }, ], [ { type: TokenType.Param, value: 'id', regexp: '', repeatable: false, optional: false, } ] ]
/:id(\d+)new对应的token数组
[ [ { type: TokenType.Param, value: 'id', regexp: '\\d+', repeatable: false, optional: false, }, { type: TokenType.Static, value: 'new' } ] ]
从上述例子中可以发现,我们主要通过token来实现对router的分级路由的存储,通过token数组来判断每级路由的内容和属性。
如果通过tokenizePath生成router可以使用的token
利用有限状态自动机生成token数组,这里就不多赘述了。详细可通过掘金博客来进行查阅。
tokensToParser
tokensToParser函数接收一个token数组和一个可选的extraOptions,在函数中会构造出path对应的正则表达式、动态参数列表keys、token对应的分数(相当于权重,该分数在后续path的比较中会用到)、一个可以从path中提取动态参数的函数(parse)、一个可以根据传入的动态参数生成path的函数(stringify),最后将其组成一个对象返回。
resolve
resolve根据传入的location进行路由匹配,找到对应的matcher的路由信息。方法接收一个location和currentLocation参数,返回一个MatcherLocation类型的对象,该对象的属性包含:name、path、params、matched、meta。
removeRoute删除路由
删除路由。接收一个matcherRef参数,removeRoute会将matcherRef对应的matcher从matcherMap和matchers中删除,并清空matcherRef对应matcher的children与alias属性。由于matcherRef对应的matcher被删除后,其子孙及别名也就没用了,也需要把他们从matcherMap中和matchers中删除。
getRoutes
获取所有match参数
getRecordMatcher
根据路由名来获取对应的matchs
insertMatcher
在添加matcher时,并不是直接matchers.add,而是根据matcher.score进行排序。比较分数时根据数组中的每一项挨个比较,不是比较总分。
总结
一开始,在vue-router通过matcher完成路由的管理、匹配操作,其中用来存储matcher的主要是通过matchers和matcherMap。matchers中权重高的matcher优先matcherMap中的使用路由表中的name当作key,只存放原始matchers.
matcher中包含了路由path对应的正则、路由分数score、动态参数列表keys、可从path中提取动态参数的parse(path)函数、可传入参数对象将其转为对应path的stringify(param)函数、父matcher(parent)、路由的标准化版本record、子matcher(children)、由别名产生的matcher。