關于 Vue Router 下手動執(zhí)行 history.replaceState 后,跳轉其它地址,再返回,路由地址指向不正確的問題解決方案

有這樣一個需求:

頁面上有很多標簽,點擊后選中,并異步調取業(yè)務接口,要求:

  • 不刷新頁面,同時將選中的標簽值反應在 URL 的 query 參數(shù)里;
  • 當跳轉其他頁面完成業(yè)務操作后,再次返回標簽頁,選中 URL 上 query 參數(shù)對應的標簽值*

通常改變 URL 使用 Vue Router(v4.x) 的 router.push()、router.replace() 方法:

router.replace({
    query: {
        tag: selectedTag.value
    }
})

但是他們都會立即跳轉頁面,可能打斷用戶的操作。JS 原生的 history.replaceState 用于操作 history 記錄,它不會立即刷新頁面,用它來替換 URL 的 query 再合適不過了:

export function updateQuery(query:{
    [key:string]: string|undefined
}={}){
    const url=new URL(window.location.href)
    // 根據(jù)方法參數(shù)重置query
    Object.keys(query).forEach(key=>{
        url.searchParams.set(key,query[key]??'')
    })
    window.history.replaceState(null, '', url)
}

在標簽上綁定click事件并調用:

updateQuery({
    tag: selectedTag.value,
})

當點擊標簽時,就會發(fā)現(xiàn)瀏覽器地址欄的 URL 如預期的發(fā)生著變化,并且頁面沒有重新加載。
但是,很快就發(fā)現(xiàn):當切換到下一個頁面,再返回(瀏覽器的返回上一頁操作),此時之前給定的參數(shù)并未出現(xiàn)再URL的query里,是的,query參數(shù)丟了

瀏覽器調試區(qū)出現(xiàn)了警告,告訴我們應該閱讀下 Vue Router 的官方說明,顯然是哪里漏了關鍵內容。在文檔里,找到了以下描述:

“Vue Router 將信息保存在 history.state 上。”
“我們使用歷史狀態(tài)(history.state)來保存導航信息,如滾動位置,以前的地址等?!?/p>

原來,Vue Router 在 history 模式下依賴 state 信息,所以若想在 Vue Router 驅動的路由框架內使用 history.replaceState()、history.pushState() 等 JS 原生方法,是需要把 history.state 帶入的。讓我們先來看看此時 history.state 里都有些什么內容:

{
    "back": "/xxxx/detail?id=546546465",
    "current": "/trade-manage/after-sale?tag=6",
    "forward": "/xxxx/detail?id=546546465",
    "replaced": true,
    "position": 51,
    "scroll": {
        "left": 0,
        "top": 0
    }
}

從語義上就可以知道,它包含了前進、后退操作指向的地址,甚至是滾動條位置等信息。通過適當?shù)恼{整這些參數(shù),Vue Router 會依照調整后的內容執(zhí)行相關操作。

如此,在執(zhí)行 history.replaceState() 前改變下 history.state.current (它表示當前地址信息)的值,再把當前的 history.state 傳入 history.replaceState() 的第一個參數(shù)來手動更新下當前路由的 history.state。這樣在跳轉到下一條路由后 Vue Router 會依據(jù)自身邏輯主動把 history.state.current 的值填充到下一條路由的 history.state.back 上,從而決定在下一條路由下執(zhí)行“回退”操作時指向的地址。經過梳理最終得到了以下方法:

export function updateQuery(query:{
    [key:string]: string|undefined
}={}){
    const url=new URL(window.location.href)
    const state=window.history.state
    // 根據(jù)方法參數(shù)重置query
    Object.keys(query).forEach(key=>{
        url.searchParams.set(key,query[key]??'')
    })
    // 變更current,在跳轉前明確當前頁面的url,包括query
    state.current=url.href.replace(new RegExp(`^${url.origin}`),'')
    // 將state置入
    window.history.replaceState(state, '', url)
}

簡單理解就是:每次變更 URL 的 query 時,同步更新下 history.state.current。

由此,問題解決,需求得到了滿足。

Refs:history.state 在 Vue Router 里的用法

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容