vue3不能使用history.pushState修改url参数踩坑

前言

在重构我的 vue-use-sync-url(辅助将数据和 url 参数进行同步的工具库)时,遇到了一个使用 window.history.pushState 来修改地址栏的 url 参数的 bug,准确来说是 vue-router 的 bug,下面就来讲讲具体是怎么回事。

问题

场景如下,有一个输入框里面输入了内容,点击搜索按钮使用 window.history.pushState 将数据同步到 url 参数上。然后再点击 go about 按钮跳转到别的页面,关键的来了,这时候你点击浏览器左上角的回退按钮回到刚才的页面,url 上的 keywords 参数变没了! 这里上个测试链接 codesandbox

<script setup>
import { ref } from "vue";
const keywords = ref("123")
const handleClick = () => {
 window.history.pushState({}, "", `${window.location.pathname}?keywords=${keywords.value}`)
}
</script>
<template>
 <input v-model="keywords" />
 <button @click="handleClick">搜索</button>
 <router-link to="/about">go about</router-link>
</template>

追根溯源

一开始想是不是我写的有问题?测试了 vue2-routerreact-router 都没有这个问题,所以我就将问题锁定在了 vue3-router 了。因为 router-link 和直接执行了 router.push 操作是一样的,所以我就去找 push 操作所在的源码位置,最终在 packages/router/src/history/html5.ts 中找到了如下代码。

可以看到在这个 push 函数中,在第 288 行,执行了一次 replace 的操作,而在第 297 行才是真正的 push 操作。我将第 288 行注释之后,上面的 demo 就跑通了,但是直觉告诉我它这里这么做是有原因的,但是想弄明白估计得将整个库的源码看完,没有这个精力。直接提了个 issue,在它的 github issue 中我发现了好几个由于这个第 288 行代码产生的问题,例如 #1416#1526#1529。维护者在我的 issue 中是这么回答的。

结合他在其它 issue 中的回答,大概是如下这么个意思。直接使用 history api,路由器是不知道的,应该避免使用,最好使用 router.push 来进行更改。还说到第 288 行对于更新当前历史记录条目是必要的,以便能够通过导航守卫取消ui 发起的导航。它允许知道导航的方向和在历史堆栈中的相对位置。不幸的是,目前还没有其他方法可以做到这一点。

我补充道,在 vue2react 中没有这个问题,你不觉得这是个 bug 吗?他说在 vue2 中使用 hisotry api 可能会产生你没有遇到过的问题,vue-routervue3 中比 vue2 拥有更多的功能等等。

解决

没办法,维护者不觉得这是个 bug,最后只能妥协使用 router.push 来解决,并将 vue-router 的依赖添加到 peerDependencies 中。在一些场景下,如果想封装一个库在各个框架中共同使用就不行了,在这里必须使用 router.push 才可以,我觉得还是不太好的。

作者:马格纳斯

%s 个评论

要回复文章请先登录注册