vue-router 升级踩坑记录

395 阅读1分钟

一个例子

Home 页面跳转到 /about 代码如下:

this.$router.push({
  path: '/about',
  query: {
    a: 123,
    b: false,
    c: null,
    d: undefined,
    e: [123, 'hello', false],
    f: [],
    g: {
      a: 'hello',
      b: 123
    },
    h: [{ a: 123, b: false, c: [123] }]
  }
})

/about 页面内执行 console.log(this.$route.query)

@3.2.0 现象

跳转后输出结果如下:

image.png

与从 Home 页面跳转时传递的参数一致。

@3.6.5 现象

跳转后输出结果如下:

image.png

与跳转时传递的参数相比,有以下几点不同:

  • number 类型的值变成了 string 类型
  • boolean 类型的值变成了 string 类型
  • 数组中的 number 值和 boolean 值也变成了 string 值
  • 数组中的 object 值保持了原样

如果 /about 页面中有如下代码,升级后不修改原代码将会掉坑里。

  • if (query.a === 123)
    @3.2.0 版本,结果为 true。
    @3.6.5 版本,结果为 false。
  • if (!query.b)
    @3.2.0 版本,query.b 为 false, !query.b 为 true。
    @3.6.5 版本,query.b 为 'false', !query.b 为 false。

源代码

通过查看 vue-router 项目的 CHANGELOG.md 文档,发现在 @3.4.0 版本时,为了修复 issue 特意将 query 的值做了转换。 vue-router/CHANGELOG.md at dev · vuejs/vue-router (github.com)

image.png

该 commit 修改内容如下:

image.png

最新的 resolveQuery 函数如下:

export function resolveQuery (
  query: ?string,
  extraQuery: Dictionary<string> = {},
  _parseQuery: ?Function
): Dictionary<string> {
  const parse = _parseQuery || parseQuery
  let parsedQuery
  try {
    parsedQuery = parse(query || '')
  } catch (e) {
    process.env.NODE_ENV !== 'production' && warn(false, e.message)
    parsedQuery = {}
  }
  for (const key in extraQuery) {
    const value = extraQuery[key]
    parsedQuery[key] = Array.isArray(value)
      ? value.map(castQueryParamValue)
      : castQueryParamValue(value)
  }
  return parsedQuery
}

const castQueryParamValue = value => (value == null || typeof value === 'object' ? value : String(value))

可以看到 vue-router 对除 value == null || typeof value === 'object' 以外的值都转成了 string。

建议

  1. 项目中 vue-router 在 @3.4.0 版本以下的,升级到 @3.4.0 以上时要检查下代码中是否有依赖 query 值为 boolean 和 number 的情况。
  2. query 的值最好只是 string 类型,或者元素为 string 的数组。如需要传递对象,可使用 JSON.stringify() 处理后传递。