乐趣区

关于前端:vueRouter-push问题的思考

背景

在开发 vue 的前端我的项目中,咱们经常应用编程式路由来实现导航页面的切换。大家基本上都会应用到 this.$router.push 的办法。
常见的应用办法是:

this.$router.push({name:'a'});

this.$router.push({path:'/a'})

在我的项目的开发过程中,我应用了 push 办法采纳下面的第二种形式,然而我书写的形式并没有带 ’/’, 我过后的路由假如为 ’/a’, 执行上面的办法,我的页面切换为 ’/b’, 这和咱们个别书写的形式不统一,然而门路跳转是失常的。

this.$router.push({path:'b'})

钻研阶段

我想晓得 path 匹配的形式是带有 ’/’ 是从根路由开始替换的,然而如果我不带 ’/’, 为什么一切正常?我查问了官网文档,官网同样也有不带 ’/’ 的写法,然而并没有解释其中具体的逻辑。

于是我就去看了官网的源码。

顺着 push 办法一路找上来,我发现了一个办法 utils/path.js 有一个解决门路的形式:
resolvePath

export function resolvePath (
  relative: string,
  base: string,
  append?: boolean
): string {const firstChar = relative.charAt(0)
  if (firstChar === '/') {return relative}

  if (firstChar === '?' || firstChar === '#') {return base + relative}

  const stack = base.split('/')

  // remove trailing segment if:
  // - not appending
  // - appending to trailing slash (last segment is empty)
  if (!append || !stack[stack.length - 1]) {stack.pop()
  }

  // resolve relative path
  const segments = relative.replace(/^\//, '').split('/')
  for (let i = 0; i < segments.length; i++) {const segment = segments[i]
    if (segment === '..') {stack.pop()
    } else if (segment !== '.') {stack.push(segment)
    }
  }

  // ensure leading slash
  if (stack[0] !== '') {stack.unshift('')
  }

  return stack.join('/')
}

我传入的 path 门路在这里失去了解析,而后恢复正常了。
起初我在官网编写的测试用例中看到了这个办法的测试代码。

describe('Path utils', () => {describe('resolvePath', () => {it('absolute', () => {const path = resolvePath('/a', '/b')
      expect(path).toBe('/a')
    })

    it('relative', () => {const path = resolvePath('c/d', '/b')
      expect(path).toBe('/c/d')
    })

    it('relative with append', () => {const path = resolvePath('c/d', '/b', true)
      expect(path).toBe('/b/c/d')
    })

    it('relative parent', () => {const path = resolvePath('../d', '/a/b/c')
      expect(path).toBe('/a/d')
    })

    it('relative parent with append', () => {const path = resolvePath('../d', '/a/b/c', true)
      expect(path).toBe('/a/b/d')
    })

    it('relative query', () => {const path = resolvePath('?foo=bar', '/a/b')
      expect(path).toBe('/a/b?foo=bar')
    })

    it('relative hash', () => {const path = resolvePath('#hi', '/a/b')
      expect(path).toBe('/a/b#hi')
    })
  })
  ...
})

结合实际代码和测试用例咱们发现:
当咱们的原门路为 /a, 当咱们 push({path:b}), 最终为生成 ’/b’
当咱们的原门路为 /a/c, 当咱们 push({path:b}), 最终为生成 ’/a/b’

当然还有其余各种状况,然而解决了我对于门路以后跳转的纳闷。大家有趣味也能够试试别的形式。’../b’ 等形式,然而官网文档上并没有标出这些应用形式,所以大家还是尽量依照规范的形式。

心愿能够解决大家对于官网文档上 path 前不带 ’/’ 的具体问题。

退出移动版