其他部分分析暂时不放了,你只需要知道关于路由加载,管理,匹配都是VueRouter创建的实例上的一个属性router.matcher做的,接下来我们主要是针对这个matcher相关代码分析。
router.matcher
VueRouter实例的两个方法match和addRoutes都是内部matcher对象暴露的方法。
只不过VueRouter的实例的addRoutes方法在调用了对应matcher对象方法后,还执行了以下代码。
if (this.history.current !== START) {
this.history.transitionTo(this.history.getCurrentLocation())
}
由于在init的时候已经执行过一次transitionTo了,所以这里减少不必要的操作,其实transitionTo里有做相同路由不跳转的处理。
其中match方法的作用为解析页面路径,获取匹配到的路由对象。这在VueRouter中起着重要作用,在每次跳转时,都需要去获取目标路径对应的路由对象,这里也实现到了动态路由匹配的功能。
而addRoutes则是动态添加路由规则的方法,这对于异步权限获取并设置对应路由很有帮助。
1. createMatcher
首先,我们来看看matcher是怎么来的。
// VueRouter constructor
this.matcher = createMatcher(options.routes || [], this)
我们知道,matcher是VueRouter实例上的一个属性,它是在构造器中用createMatcher方法创建的。
具体实现逻辑:
- 首先根据传入的
options.routes构建了pathList,pathMap,nameMap- 然后创建了
match和addRoutes方法并返回
可以猜得出来,我们配置的options.routes在这里之后就没啥用了。
因为它内部浅拷贝了options.routes并且生成了所有路由对象的map,就相当于是私有属性了。而之后对路由的处理都是基于这些路由对象来的,所以配置项options.routes到这里也就没啥用了。
说白了就你后面想通过配置项options的引用去修改或者删除某个路由是不太可能的了。
这里的
options是指我们在new VueRouter(options)时传入的配置参数
2. addRoutes: (routes: Array) => void
matcher暴露出来的能够修改到内部的路由对象map的就只有这个方法了,其作用是扩充原来的路由对象map。
function addRoutes (routes) {
createRouteMap(routes, pathList, pathMap, nameMap)
}
这里引用的pathList, pathMap,nameMap都是外部作用域(createMatcher方法内作用域)的变量,也就是说他在更新这些变量。
addRoutes为我们提供了异步增加路由的方法,这在某些场合下很有用。
这里提一点就是在方法createRouteMap的实现中,对于后来加的path相同的路由是不会覆盖掉原来的路由的(在pathMap和pathList中),同name的也一样(在nameMap中)。
3. match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route
其主要逻辑在于根据传入的第一个参数获取其路径path,并根据path从pathMap中取出匹配到的路由对象并返回。
另外还有根据name匹配的逻辑。
总结
// VueRouter
class VueRouter {
// ...
match(raw, current, redirectedFrom) {
return this.matcher.match(raw, current, redirectedFrom)
}
push(location, onComplete, onAbort) {
// ...
this.history.push(location, onComplete, onAbort)
// this.history.push 主要是由 history.transitionTo 实现
}
}
matcher.match方法是比较核心的方法,在路由跳转的基本实现方法history.transitionTo中,就是用this.router.match来获取目标路由的。
function createMatcher (routes) {
const { pathList, pathMap, nameMap } = createRouteMap(routes)
// ...
return {
match,
addRoutes
}
}
这里我们可以很清晰的看出来,matcher并没有暴露出修改路由表的方法。
但实际上我们在运用的过程中,可能会出现以下情景:
未登录前,我们加载的是路由表1。
登录后,我们的路由表增加了,并且原来的路由可能组件也改变了,变成了路由表2。
我们是可以异步加载路由,用addRoutes。但是之前也提到了,相同path,name是不会进行替换的。
所以会出现同path,name的路由仍然没有进行更新。
那解决方法呢?
就在于这个matcher,既然匹配路由是靠matcher,并且matcher在运行时也没有依赖到其他模块。那么我们根据新的routes自己create一个matcher对原来的进行替换,那么不就相当于更新了路由表吗。
但是VueRouter并没有将该方法export出来或挂在VueRouter上,我们也不能直接引用vue-router/src/create-matcher.js对其进行加载,因为他是用flow写的。
import VueRouter from 'vue-router'
import router form './router'
const newRouter = new Router({
routes: newRoutes
})
router.matcher = newRouter.matcher
router.push('/changed-path')
我们只有新建一个VueRouter实例,来获取新的matcher。
OVER! ( * ┒ * )