一、复现路径
用 react 的 useNavigate 跳转到一个 vue 路由,vue 页面内用 router.push 就会跳转 ${host}undefined,如 juejin.cnundefined ,直接无法访问。
二、原因
vue-router push 方法两次跳转
function push(to, data) {
const currentState = assign({},
historyState.value, history.state, {
forward: to,
scroll: computeScrollPosition(),
});
changeLocation(currentState.current, currentState, true);
const state = assign({}, buildState(currentLocation.value, to, null), { position: currentState.position + 1 }, data);
changeLocation(to, state, false);
currentLocation.value = to;
}
第一个 changeLocation(currentState.current, currentState, true) currentState.current 是 undefined,而 changeLocation 用 createBaseLocation() + base + to 组装url,直接拼成 undefined。
currentState.current undefined 是因为 react-router 用的 history 不会给 state 赋值 current
function getHistoryStateAndUrl(nextLocation, index) {
return [
{
usr: nextLocation.state,
key: nextLocation.key,
idx: index,
},
createHref(nextLocation),
];
}
function push(to, state) {
var _getHistoryStateAndUr = getHistoryStateAndUrl(
nextLocation,
index + 1
),
historyState = _getHistoryStateAndUr[0],
url = _getHistoryStateAndUr[1];
globalHistory.pushState(historyState, "", url);
}
精简了一下代码,historyState 只有 usr, key, idx 三个属性,没有 current
三、解决
如果改 vue,用 router.replace 不用 router.push 能行,还可以考虑给 vue-router 加点兼容
if (currentState.current) {
changeLocation(currentState.current, currentState, true);
}
还可以改 history 把 current 加上。
不过改动都有点大,考虑到 vue react 并存也只是临时状态,最好选择监听 popstate 事件纠正 state
useEffect(() => {
window.addEventListener('popstate', ({ state }) => {
setTimeout(() => {
// 纠正react跳转state
if (!history.state.current) {
history.replaceState(
null,
null,
`${window.location.pathname}${window.location.search}`
)
}
}, 500)
})
}, [])