vue-router 源码分析——6.命名路由

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

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

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

源码实现分析:

  • 官方例子
const router = new VueRouter({
  routes: [
    {
      path: '/user/:userId',
      name: 'user',
      component: User
    }
  ]
})

<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
router.push({ name: 'user', params: { userId: 123 } })
  • 回顾一下第一章,即创建vue-router 实例时内部发生了什么。router创建了一个匹配器 this.matcher,在这个内部创建了非常重要的三个数据:pathList、pathMap和nameMap。前两个之前已经介绍过了,现在介绍一下nameMap的数据结构。
  • 从下面的源码可以看出,nameMap 是以使用者定义的每个route的name(如果有)作为key,value为每个route的record。同时name也会添加到record中。
// ./create-route-map.js
export function createRouteMap(
    routes: Array<RouteConfig>,
    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)
    reoutes.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 record: RouteRecord = {
        name,
        ...
    }
    if (name) {
        if (!nameMap[name]) {
            nameMap[name] = record        
        } else if (...) {...}
    }
}
// ./history/hash.js
export class HashHistory extends History {
    ...
    push(location: RawLocation, onComplete?: Function, onAbort?: Function)) {
         ...
         this.transitionTo(
             location,
             route => {
                 ...             
             }         
         )   
    }
}

// ./history/base.js
export class History {
    ...
    transitionTo(
        location: RawLocation,
        onComplete?: Function,
        onAbort?: Function
    ) {
        let route
        try {
            route = this.router.match(location, this.current) // 创建新路由
        }    
    }
}
  • 在创建新路由时,如果存在name,则通过nameMap来查找并获得相关数据(record)。
  • 通过下面的源码分析,知道了vue-router的两种匹配方式(name和path)的处理逻辑。命名路由name是使用哈希算法来进行匹配,而路径路由path是遍历数组进行匹配。在匹配时,以name匹配优先。
// ./router.js
export default class VueRoute {
    ..
    match(raw: RawLocation, current?: Route, redirectedFrom?: Location): Route {
        return this.matcher.match(raw, current, redirectedFrom)    
    }
}

// ./create-matcher.js
export function createMatcher {
    routes: Array<RouteConfig>,
    router: VueRouter
}: Matcher {
    const { pathList, pathMap, nameMap } = createRouteMap(routes)
    function match(
        raw: RawLocation,
        currentRoute?: Route,
        redirectedFrom?: Location            
    ): Route {
        const location = normalizeLocation(raw, currentRoute, false, router)
        const { name } = location
        if (name) {
            const record = nameMap[name] // 通过nameMap来查找并获得record
            ...
            location.path = fillParams(record.path, location.params, `named route "${name}"`)
            return _createRoute(record, location, redirectedFrom)
        } else if (location.path) {...}
    }
}

总结

  • 在路由初始化时,收集所有用户定义的命名路由记录到 nameMap 字典结构中。
  • 在路由匹配时,通过name作为key,从 nameMap 中取出对应的路由记录,以此来生成对应url的路由。
  • 命名路由的匹配时间复杂度要优于路径匹配(hashmap-getter 和 数组遍历),所以理论上命名路由的匹配时间要少于路径匹配。如果项目有大量路径匹配的路由时,可以转换成命名路由来优化匹配。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值