vue-router3源码注解系列 /src/create-route-map.js

本文详细探讨了vue-router3中create-route-map源码,揭示了路由映射的实现原理,包括如何构建路由树,解析动态段,以及路由匹配的过程。通过分析,有助于深化对vue-router工作机制的理解。
/* @flow */

/*
  用于路径匹配的正则表达式对象。
*/
import Regexp from 'path-to-regexp'
//用于清理 uri 上连续重复的 / 。
import {
   
    cleanPath } from './util/path'
//断言,警告。
import {
   
    assert, warn } from './util/warn'

/*
  createRouteMap() 函数: 
  第一个参数 routes 就是 new VueRouter( { routes: [xxxx] } ) 中的 routes。
*/
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>,
} {
   
   
  // the path list is used to control path matching priority
  //存放所有路由的 path 。
  const pathList: Array<string> = oldPathList || []
  // $flow-disable-line
  //以 path 作为 key,存放所有的路由描述对象。
  const pathMap: Dictionary<RouteRecord> = oldPathMap || Object.create(null)
  // $flow-disable-line
  //以 name 作为 key,存放所有路由描述对象。
  const nameMap: Dictionary<RouteRecord> = oldNameMap || Object.create(null)

  //routes 是一个数组对象。也就是用户手写的 new VueRouter( { routes: [xxx] } ) 的 routes 配置数据
  //遍历routes数组的数据,将所有元素转化为 router record 对象。且会被记录到 pathMap, nameMap 对象中。
  routes.forEach((route) => {
   
   
    //pathList: 全局的 pathList,所有路由创建过程中是同一个 pathList.
    //pathMap:  全局的 pathMap, 所有路由创建过程中是同一个 pathMap.
    //nameMap:  全局的 nameMap, 所有路由创建过程中是同一个 nameMap.
    //route:    就是要转化为的 router record 对象的数据。
    //parentRoute:表示父 route 数据转化成的 router record 对象。
    addRouteRecord(pathList, pathMap, nameMap, route, parentRoute)
  })

  /**
   * 这一段主要处理 pathList 中的 path == ‘*’ 的路径,且移到数组末尾。
   */
  //依次遍历 pathList。 pathList 中元素都是完整绝对路径。
  // 如果 pathList 中存在 path 路径为 “*”,则移除该元素,并且追加到 pathList 数组末尾。
  for (let i = 0, l = pathList.length; i < l; i++) {
   
   
    if (pathList[i] === '*') {
   
   
      //先移除第 i 个元素,pathList.splice() 返回被移除元素的数组。
      //因为只移除了一个,则获取下标为0的元素,然后塞到数组的末尾。
      pathList.push(pathList.splice(i, 1)[0])
      //之所以要 l--, 是因为 l ~ length 的元素就是 * 号,已经处理过了。
      //如果 l 不 --, 存在多个 * 的情况,则会死循环。
      l--
      //此时i+1 ~ length-1 的元素已经迁移。后一个元素已经占在了 i 位置。
      //  所以需要 i--,然后下一轮循环就能取到下一个没有判断*的元素。
      i--
    }
  }

  /*
    如果是开发环境,且 pathList 中 path 元素,不是以 * 或者 / 开头,则报警告。
  */
  if (process.env.NODE_ENV === 'development') {
   
   
    // warn if routes do not include leading slashes
    const found = pathList
      // check for missing leading slash
      .filter(
        (path) => path && path.charAt(0) !== '*' && path.charAt
<think> 我们正在处理Vue Router中出现的重复导航错误。根据引用内容,解决这个问题的常见方法是重写VueRouter原型上的push方法,以捕获并忽略NavigationDuplicated错误。 具体步骤: 1. 在定义路由的文件(通常是router/index.js)中,获取原始的push方法。 2. 重写VueRouter.prototype.push方法,使其在调用时捕获错误,并忽略特定的NavigationDuplicated错误。 3. 其他错误仍然抛出。 根据引用[2][3][4][5]的方法,我们可以这样实现: 需要注意的是,在Vue Router 3.x版本中,这个错误会以Promise rejection的形式抛出。因此,我们捕获这个错误并不再抛出即可。 但是,请注意:在Vue Router 4.x中,这个错误不会抛出(而是内部处理了),所以如果你使用的是Vue3Vue Router4,可能不会遇到这个问题。不过,我们的用户可能还在使用Vue2和Vue Router3。 因此,我们提供以下解决方案: 在router/index.js中,添加以下代码: </think> 要解决 Vue Router 中出现的 `NavigationDuplicated: Avoided redundant navigation to current location: "/personal"` 错误,请按照以下步骤操作: ### 解决方案步骤 1. **修改 VueRouter 原型方法**(最佳全局方案) 在路由配置文件(通常是 `router/index.js`)中添加以下代码: ```javascript import VueRouter from &#39;vue-router&#39;; // 保存原始 push 方法 const originalPush = VueRouter.prototype.push; // 重写 push 方法 VueRouter.prototype.push = function push(location) { return originalPush.call(this, location).catch(err => { // 仅忽略导航重复错误 if (err.name !== &#39;NavigationDuplicated&#39;) throw err; }); }; ``` 此方案通过全局捕获冗余导航错误有效解决问题[^2][^3][^4][^5]。 2. **添加路由跳转前检查**(局部解决方案) 在触发导航的代码位置添加路径检查: ```javascript // 在组件方法中 navigateToPersonal() { if (this.$route.path !== &#39;/personal&#39;) { this.$router.push(&#39;/personal&#39;); } } ``` 3. **使用 replace 替代 push** 当不需要保留历史记录时: ```javascript this.$router.replace(&#39;/personal&#39;); // 替换当前路由而非添加新记录 ``` 4. **升级 Vue Router**(如使用旧版本) 在终端执行: ```bash npm install vue-router@^3.6.5 # Vue 2 推荐版本 ``` ### 错误原因分析 此错误在以下情况触发: - 重复点击指向当前路由的导航链接 - 编程式导航(`$router.push`)指向当前激活路径 - Vue Router3.1.0 版本引入了 Promise 返回机制[^1][^3] - 路由路径完全匹配(包括查询参数等) > **关键提示**:方案1 是最推荐的全局解决方案,可避免修改多个组件代码[^2][^5]。在 Vue Router 4.x(Vue3)中该问题已优化,无需额外处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值