【vue-router源码】系列文章将带你从0开始了解vue-router
的具体实现。该系列文章源码参考vue-router v4.0.15
。
源码地址:https://github.com/vuejs/router
阅读该文章的前提是你最好了解vue-router
的基本使用,如果你没有使用过的话,可通过vue-router官网学习下。
该篇文章将分析router.addRoute
、router.removeRoute
、router.hasRoute
、router.getRoutes
的实现。
addRoute
addRoute
添加路由时,如果第一个参数为路由name
,那么会添加一个嵌套路由;否则添加的是个非嵌套路由。// 添加非嵌套路由
router.addRoute({ name: 'admin', path: '/admin', component: Admin })
// 添加嵌套路由
router.addRoute('admin', { path: 'settings', component: AdminSettings })
以上代码等同于:
router.addRoute({
name: 'admin',
path: '/admin',
component: Admin,
children: [{ path: 'settings', component: AdminSettings }],
})
removeRoute
router.removeRoute('admin')
hasRoute
router.hasRoute('admin')
getRoutes
router.getRoutes()
addRoute
可接受两个参数:parentOrRoute
(父路由的name或一个新的路由,如果是父路由的name,name第二个参数是必须的)、record
(要添加的路由)。返回一个删除新增路由的函数。
function addRoute(
parentOrRoute: RouteRecordName | RouteRecordRaw,
route?: RouteRecordRaw
) {
let parent: Parameters<typeof matcher['addRoute']>[1] | undefined
let record: RouteRecordRaw
// 如果parentOrRoute是路由名称,parent为parentOrRoute对应的matcher,被添加的route是个嵌套路由
if (isRouteName(parentOrRoute)) {
parent = matcher.getRecordMatcher(parentOrRoute)
record = route!
} else { // 如果parentOrRoute不是路由名称,parentOrRoute就是要添加的路由
record = parentOrRoute
}
// 调用matcher.addRoute添加新的记录,返回一个移除路由的函数
return matcher.addRoute(record, parent)
}
在定义parent
时,使用了一个Paramerer<Type>
类型,对于该类型的使用可参考https://www.typescriptlang.org/docs/handbook/utility-types.html#parameterstype。在该方法中,parent
的类型会取matcher.addRoute
方法中的第2个参数的类型。
isRouteName
:通过判断name
是否为string
或symbol
类型,来决定是不是routeName
。
export function isRouteName(name: any): name is RouteRecordName {
return typeof name === 'string' || typeof name === 'symbol'
}
删除路由。removeRoute
接收一个name
(现有路由的名称)参数。
function removeRoute(name: RouteRecordName) {
// 根据name获取对应的routeRecordMatcher
const recordMatcher = matcher.getRecordMatcher(name)
if (recordMatcher) {
// 如果存在recordMatcher,调用matcher.removeRoute
matcher.removeRoute(recordMatcher)
} else if (__DEV__) {
warn(`Cannot remove non-existent route "${String(name)}"`)
}
}
用于判断路由是否存在。hasRoute
接收一个name字符串,返回一个boolen
值。
通过matcher.getRecordMatcher
来获取对应的matcher
,在matcher.getRecordMatcher
会在matcherMap
中取寻找对应的matcher
,如果没有找到说明路由不存在。
function hasRoute(name: RouteRecordName): boolean {
return !!matcher.getRecordMatcher(name)
}
获取标准化后的路由列表。标准化后的路由会被存储到matcher.record
中。
function getRoutes() {
// 遍历matchers,routeMatcher.record中存储着路由的标准化版本
return matcher.getRoutes().map(routeMatcher => routeMatcher.record)
}
router.addRoute
、router.removeRoute
、router.hasRoute
、router.getRoutes
几个API全都依赖matcher
实现,可见matcher
是vue-router
的核心,如果你不了解matcher
,建议回顾下之前的文章。