vue-router 源码分析——1. 路由匹配

这是对vue-router 3 版本的源码分析。
本次分析会按以下方法进行:

  1. 按官网的使用文档顺序,围绕着某一功能点进行分析。这样不仅能学习优秀的项目源码,更能加深对项目的某个功能是如何实现的理解。这个对自己的技能提升,甚至面试时的回答都非常有帮助。
  2. 在围绕某个功能展开讲解时,所有不相干的内容都会暂时去掉,等后续涉及到对应的功能时再加上。这样最大的好处就是能循序渐进地学习,同时也不会被不相干的内容影响。省略的内容都会在代码中以…表示。
  3. 每段代码的开头都会说明它所在的文件目录,方便定位和查阅。如果一个函数内容有多个函数引用,这些都会放在同一个代码块中进行分析,不同路径的内容会在其头部加上所在的文件目录。

本章讲解router中创建vue-router 实例时内部发生了什么。
另外我的vuex3源码分析也发布完了,欢迎大家学习:
vuex3 最全面最透彻的源码分析
还有vue-router的源码分析:
vue-router 源码分析——1. 路由匹配
vue-router 源码分析——2. router-link 组件是如何实现导航的
vue-router 源码分析——3. 动态路由匹配
vue-router 源码分析——4.嵌套路由

创建vue-router 实例时内部发生了什么

  • 假设最基本的情况,即官网中的入门示例:
const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]
const router = new VueRouter({
  routes // (缩写) 相当于 routes: routes
})
  • 在实例化的过程中创建matcher 匹配器,调用了 createMatcher 函数
// ./router.js
import type { Matcher } from './create-matcher'
export default class VueRouter {
    matcher: Matcher
    constructor (options: RouterOptions = {}) {
        this.matcher = createMatcher(options.routes || [], this)  
    }
}
  • 在 createMatcher 函数中调用 createRouteMap 函数创建了一些和path相关的数据,并返回包含自己内容定义的一些函数组成的对象。
// createMatcher函数 ./create-matcher.js
import { createRouteMap } from './create-route-map'
export function createMatcher(routes, route): {
    const {pathList, pathMap, nameMap } = createRouteMap(routes)
    function match() {}
    function addRoute() {}
    function getRoutes() {}
    function addRoutes() {}
    return {
        match,
        addRoute,
        getRoutes,
        addRoutes    
    }
}
  • createRouteMap函数利用routes数据得出上面需要的对象内容(pathList, pathMap, nameMap),对应 ./create-route-map.js 文件。
  • 内部遍历routes => route,并调用 addRouteRecord 函数。
  • 对每个route的path,调用 normalizePath 函数规范化。
  • 构建一个 record 对象,基本内容还是和route一样,比如path, component。component这里有一个逻辑或运算符,是用来处理命名视图的,可以先不管。
  • pathList 记录每个record的path。
  • pathMap 记录record的path和record的映射关系。
  • nameMap 记录name(命名路由)和recoed的映射关系。
export function createRouteMap(
    routes: Array<RouteConfig>,
    // 下面的其他参数可先不管,因为只传了routes入参,都可看做undefine or any
    oldPathList?: Array<string>,
    oldPathMap?: Dictionary<RouteRecord>,
    oldNameMap?: Dictionary<RouteRecord>,
    parentRoute?: RouteRecord 
): {
    pathList: Array<string>,
    pathMap: Dictionary<RouteRecord>,
    nameMap: Dictionary<RouteRecord>
} {
    // 初始化都是空数组和空字典
    const pathList: Array<string> = oldPathList || []
    const pathMap: Dictionary<RouteRecord> = oldPathMap || Object.create(null)
    const nameMap: Dictionary<RouteRecord> = oldNameMap || Object.create(null)
    
    routes.forEach(route => {
        addRouteRecord(pathList, pathMap, nameMap, route, parentRoute)    
    })
    return {
        pathList,
        pathMap,
        nameMap    
    }
}

function addRouteRecord(
    pathList: Array<string>,
    pathMap: Dictionary<RouteRecord>,
    nameMap: Dictionary<RouteRecord>,
    route: RouteConfig,
    parent?: RouteRecord,
    matchAs?: string
) {
    const { path, name } = route
    const pathToRegexpOptions = {}
    // path 规范化
    const normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict)
    const record: RouteRecord = {
        path: normalizedPaath,
        components: route.components || { default: route.component },
        ...
    }
    // 记录 pathList 和 pathMap 的内容
    if (!pathMap[record.path]) {
        pathList.push(record.path)
        pathMap[record.path] = record    
    }
}

function normalizePath(
    path: string,
    parent?: RouteRecord,
    strict?: boolean
) {
    if (!strict) path = path.replace(/\/$/, '') // 将path尾部的 / 去掉(如果有)
    if (path[0] == '/') return path
}
  • 至此,router在初始化时,创建了一个 VueRouter类,里面有一个 matcher属性,包含了用户定义的路由的path、components和相关的匹配逻辑函数,以及三张路由记录表。
  • 下一章会分析 router-link 组件是如何实现导航的。
  • 50
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值