Vue-router create-route-map 源码分享

create-route-map

/**
 * 函数返回3个重要的参数:pathList、pathMap、nameMap
 * 返回结果示例如下:
 * pathList: ['', '/a/a1', '/a', '/b', ...]
 * pathMap: {'': {...}, '/a/a1': {...}, ...}
 * nameMap: {'main': {...}, 'nameA': {...}, ...}
 */

export function createRouteMap (
  routes: Array<RouteConfig>,
  oldPathList?: Array<string>,
  oldPathMap?: Dictionary<RouteRecord>,
  oldNameMap?: Dictionary<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 的遍历调用 addRouteRecord
  routes.forEach(route => {
    addRouteRecord(pathList, pathMap, nameMap, route)
  })

  // 确保 path: '*' 404 能在队列尾部
  for (let i = 0, l = pathList.length; i < l; i++) {
    if (pathList[i] === '*') {
      pathList.push(pathList.splice(i, 1)[0])
      l--
      i--
    }
  }

  return {
    pathList,
    pathMap,
    nameMap
  }
}
复制代码

addRouteRecord

function addRouteRecord (
  pathList: Array<string>,
  pathMap: Dictionary<RouteRecord>,
  nameMap: Dictionary<RouteRecord>,
  route: RouteConfig,
  parent?: RouteRecord,
  matchAs?: string
) {
  // example:
  // route: {
  // 	path: '/a',
  // 	name: 'nameA',
  // 	component: {},
  // 	alias: '/b',
  // 	children: []
  // }
  const { path, name } = route

  // 2.6.0+
  // 编译正则的选项
  const pathToRegexpOptions: PathToRegexpOptions = route.pathToRegexpOptions || {}

  // 返回处理过的 path 字段,具体看后面分析
  const normalizedPath = normalizePath(
    path,
    parent,
    pathToRegexpOptions.strict
  )

  // 2.6.0+
  // 匹配规则是否大小写敏感?(默认值:false)
  if (typeof route.caseSensitive === 'boolean') {
    pathToRegexpOptions.sensitive = route.caseSensitive
  }

  const record: RouteRecord = {
    path: normalizedPath,

    // 主要目的就是把 url 转为正则表达式
    regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
    components: route.components || { default: route.component },
    instances: {},
    name,
    parent,
    matchAs,
    redirect: route.redirect,
    beforeEnter: route.beforeEnter,

    // 路由元信息,官方讲得通俗易懂
    // 参考 https://router.vuejs.org/zh/guide/advanced/meta.html#%E8%B7%AF%E7%94%B1%E5%85%83%E4%BF%A1%E6%81%AF
    meta: route.meta || {},

    // 路由组件传参,用于解耦组件与 $route
    // 参考 https://router.vuejs.org/zh/guide/essentials/passing-props.html#%E5%B8%83%E5%B0%94%E6%A8%A1%E5%BC%8F
    props: route.props == null
      ? {}
      : route.components
        ? route.props
        : { default: route.props }
  }

  if (route.children) {
    // 如果路由已命名,不重定向且具有默认子路由。当用户通过路由名的方式导航到该路由,默认子路由不会被加载
    // :to="{name: route.name}"
    route.children.forEach(child => {
      const childMatchAs = matchAs
        ? cleanPath(`${matchAs}/${child.path}`)
        : undefined


      // 遍历子路由。所以最后的 pathList 可以看到子节点会在队列头部
      addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs)
    })
  }

  if (route.alias !== undefined) {
    const aliases = Array.isArray(route.alias)
      ? route.alias
      : [route.alias]

    // 其实别名的处理也很简单,创建 path 名不同但映射相同的路由
    aliases.forEach(alias => {
      const aliasRoute = {
        path: alias,
        children: route.children
      }
      addRouteRecord(
        pathList,
        pathMap,
        nameMap,
        aliasRoute,
        parent,
        record.path || '/' // matchAs
      )
    })
  }

  // pathMap 是 path 与路由的映射表
  if (!pathMap[record.path]) {
    pathList.push(record.path)
    pathMap[record.path] = record
  }

  // nameMap 是 name 与路由的映射表
  if (name) {
    if (!nameMap[name]) {
      nameMap[name] = record
    }
  }
}
复制代码

normalizePath

function normalizePath (path: string, parent?: RouteRecord, strict?: boolean): string {
  if (!strict) path = path.replace(/\/$/, '')

  // 如果以 / 开头,直接返回 path,也就是为什么子路由不让加 / 的原因
  if (path[0] === '/') return path

  // 如果不存在父路由,则是根节点
  if (parent == null) return path
  return cleanPath(`${parent.path}/${path}`)
}
复制代码
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值