vue-router4使用router.replace传入字符串时数据丢失

vue-router4使用router.replace传入字符串时数据丢失从这一步开始,matcherLocation里面就只从parseURL的返回值里面取了path一个属性,我们的query:{id:123},就已经丢失了,后面的代码里面取到的path就已经是/home了,同理router.push({path:’/home?id=123′})这…

背景

最近在使用vue-router4的时候有遇到一种写法

router.replace('/home?id=123') 

这种写法导致了一个问题,就是路由会跳转到 /home,后面的数据就丢失了,但是把replace换成push(router.push('/home?id=123') )就没问题,那这两个api在执行的时候会有些什么不同呢?又是什么导致了这种写法的错误?下面是查看vue-router源码所得到的答案

分析

我们直接来到replacepush这两个api的入口处

// vue-router@v4.0.0
// src/router.ts
function push(to: RouteLocationRaw | RouteLocation) {
    return pushWithRedirect(to)
}

function replace(to: RouteLocationRaw | RouteLocationNormalized) {
    return push(assign(locationAsObject(to), { replace: true }))
}

可以看到replace其实也会调用push,只是会通过locationAsObject将我们传入的值转为object然后还多了一个{replace:true}

function locationAsObject(
    to: RouteLocationRaw | RouteLocationNormalized
): Exclude<RouteLocationRaw, string> | RouteLocationNormalized {
    return typeof to === 'string' ? { path: to } : assign({}, to)
}

所以在调用push的时候我们传入的to就已经变成了

{
    path:'/home?id=123',
    replace:true
}

这和直接调用router.push('/home?id=123'),所接收到的to就已经不同了, 那么问题必然就在这不同之处了,让我们继续往下看,来到pushWithRedirect函数里面

// src/router.ts
function pushWithRedirect( to: RouteLocationRaw | RouteLocation, redirectedFrom?: RouteLocation ): Promise<NavigationFailure | void | undefined> {
    const targetLocation: RouteLocation = (pendingLocation = resolve(to))
    ...
}

这里会先调用resolve对我们的传入进行处理,所以我们进入到resolve

// src/router.ts
function resolve( rawLocation: Readonly<RouteLocationRaw>, currentLocation?: RouteLocationNormalizedLoaded ): RouteLocation & { href: string } {
    ...
    if (typeof rawLocation === 'string') {...}
    if ('path' in rawLocation) {...}
    ...
}

从这两个if可以看到,根据我们传入的to的类型会走到不同的分支,那么可以推断出router.replace('/home?id=123') router.push('/home?id=123') 到了这步会走到两个不同的分支(因为replace会调用locationAsObject)

当使用replace的时候resolve接收到的是{path:'/home?id=123',replace:true},而使用pushresolve接收到的是'/home?id=123'

我们先来看if ('path' in rawLocation)这个分支,也就是开头的用法会走到的分支

// src/router.ts resolve
if ('path' in rawLocation) {
  ...
  matcherLocation = assign({}, rawLocation, {
    path: parseURL(parseQuery, rawLocation.path, currentLocation.path).path,
  })
}

可以看到这一步是创建了一个变量matcherLocation,然后调用了parseURL处理我们传入的path,然后得到返回值后取了path属性,那么我们就去parseURL看下,到底做了些什么处理

// src/location.ts
export function parseURL( parseQuery: (search: string) => LocationQuery, location: string, currentLocation: string = '/' ): LocationNormalized {
  let path: string | undefined,
    query: LocationQuery = {},
    searchString = '',
    hash = ''
    
  const searchPos = location.indexOf('?')
  const hashPos = location.indexOf('#', searchPos > -1 ? searchPos : 0)

  if (searchPos > -1) {
    // 可以看到在这一步,path属性从'/home?id=123'变成了'/home'
    path = location.slice(0, searchPos)
    searchString = location.slice(
      searchPos + 1,
      hashPos > -1 ? hashPos : location.length
    )
    // searchString -> id=123
    query = parseQuery(searchString)
  }
  
  ...

  return {
    fullPath: path + (searchString && '?') + searchString + hash,
    path,
    query,
    hash,
  }
}

经过parseURL转换后我们的to变成了

{
    fullPath:'/home?id=123',
    path:'/home',
    query:{
        id:123
    },
    hash:'',
}

然后我们回到src/router.ts resolve

// src/router.ts resolve
if ('path' in rawLocation) {
  ...
  matcherLocation = assign({}, rawLocation, {
    path: parseURL(parseQuery, rawLocation.path, currentLocation.path).path,
  })
}

从这一步开始,matcherLocation里面就只从parseURL的返回值里面取了path一个属性,我们的query:{id:123},就已经丢失了,后面的代码里面取到的path就已经是/home了,同理router.push({path:'/home?id=123'})这种写法也会获取不到id。 自此,这个问题就找到答案了,至于为什么使用router.push(string)就不会有这个问题,答案在src/router.ts resolve中另外一个if分支里面

总结

其实vue-router的文档上已经介绍过这个api的使用方法了

// 字符串
router.push('home')

// 对象
router.push({ path: 'home' })

// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})

// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})

所以…

今天的文章vue-router4使用router.replace传入字符串时数据丢失分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/17937.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注