前端 Vue路由返回恢復(fù)頁(yè)面狀態(tài)的實(shí)現(xiàn)方案

來(lái)源 | https://www.cnblogs.com/skuld-yi/archive/2021/07/13/15004664.html
需求描述
方案一:將搜索參數(shù)存儲(chǔ)在路由參數(shù)(route.query)中,加載頁(yè)面時(shí)根據(jù)參數(shù)搜索 優(yōu)點(diǎn):刷新不影響;實(shí)現(xiàn)簡(jiǎn)單 缺點(diǎn):參數(shù)只能是基礎(chǔ)類型、長(zhǎng)度受限;路徑看起來(lái)比較難看;只對(duì)瀏覽器返回有效,手動(dòng)跳轉(zhuǎn)回首頁(yè)不行 方案二:使用路由守衛(wèi)鉤子,在離開(kāi)頁(yè)面前本地存儲(chǔ)頁(yè)面參數(shù)(vuex、Local Storage 等等) 優(yōu)點(diǎn):參數(shù)類型長(zhǎng)度都比較自由;路徑看起來(lái)清爽美觀;對(duì)任意方式返回主頁(yè)都有效 缺點(diǎn):需要額外進(jìn)行數(shù)據(jù)存儲(chǔ)操作,如果使用store模式或vuex則刷新頁(yè)面失效
方案一:路由參數(shù)
// 搜索頁(yè)面search(param) {// 其他處理this.$router.push({name: "Index",query: { ...this.queryParam }, // 將對(duì)象展開(kāi)為鍵值});},
這里要注意 query 傳參和 params 傳參的區(qū)別:前者的參數(shù)會(huì)以 ?k1=v1&k2=v2 的形式續(xù)在路徑后面,能直接在地址欄中看到,因此不受頁(yè)面跳轉(zhuǎn)、刷新影響;后者只在第一次跳轉(zhuǎn)到對(duì)應(yīng)頁(yè)面時(shí)起作用,再刷新跳轉(zhuǎn)就沒(méi)有了。
因此這里要使用 query 傳參。如果把參數(shù)按照格式手動(dòng)寫(xiě)在 path 中也是可以的,但易讀性和擴(kuò)展性明顯更差,除非只有一兩個(gè)簡(jiǎn)單參數(shù),否則不推薦。
另外,由于這個(gè)參數(shù)是要放進(jìn)路徑里的,因此只能是基本類型的鍵值對(duì),數(shù)組或?qū)ο蟛荒芎芎玫刂С帧?/span>
如果參數(shù)簡(jiǎn)單,可以將相應(yīng)的對(duì)象展開(kāi)當(dāng)做參數(shù)(需要保證不同對(duì)象中沒(méi)有重名鍵),但在跳轉(zhuǎn)到的搜索結(jié)果頁(yè)面中讀取時(shí),就只能逐個(gè)屬性的獲取。
// 搜索結(jié)果頁(yè)面mounted() {// 區(qū)分 $route 和 $routerif (this.$route.query.type) {let type = this.$route.query.type;let keyword = this.$route.query.keyword;// ...逐一獲取各個(gè)參數(shù)// 進(jìn)行搜索操作} else {// 沒(méi)有搜索參數(shù)(因?yàn)槲疫@搜索結(jié)果和主頁(yè)是同一個(gè)頁(yè)面,所以有可能只是正常打開(kāi)主頁(yè))}},
方案二:本地存儲(chǔ)參數(shù)
由于我這想存的參數(shù)是三個(gè)對(duì)象,展開(kāi)成鍵值取著又太不方便,所以使用了這種方案。
由于項(xiàng)目里本來(lái)也使用了 vuex,就順便存在了 vuex 里面,根據(jù)實(shí)際情況存在哪兒都行。
vuex 的缺點(diǎn)是一刷新就刷沒(méi)了,對(duì)于搜索結(jié)果這種優(yōu)化體驗(yàn)性質(zhì)的功能影響不大;如果有對(duì)應(yīng)需求可以存在 local storage 里面。
因?yàn)槲业男枨笾杏泻芏嘀蟹绞礁淖儏?shù),在改變時(shí)存儲(chǔ)參數(shù)太麻煩,而且容易出錯(cuò)或遺漏。因此這里選擇在路由跳轉(zhuǎn)之前再統(tǒng)一存儲(chǔ)所需參數(shù)。
Vue Router 提供了路由導(dǎo)航守衛(wèi)系列 API 來(lái)實(shí)現(xiàn)相應(yīng)功能,具體包括全局的前置/解析/后置守衛(wèi)、路由配置守衛(wèi)、組件守衛(wèi)等方式。
所謂”守衛(wèi)“,其實(shí)相當(dāng)于渲染過(guò)程中的”鉤子“,與熟悉的 created, mounted 一樣。
完整的導(dǎo)航解析流程:
導(dǎo)航被觸發(fā)。
在失活的組件里調(diào)用 beforeRouteLeave 守衛(wèi)。
調(diào)用全局的 beforeEach 守衛(wèi)。
在重用的組件里調(diào)用 beforeRouteUpdate 守衛(wèi) (2.2+)。
在路由配置里調(diào)用 beforeEnter。
解析異步路由組件。
在被激活的組件里調(diào)用 beforeRouteEnter。
調(diào)用全局的 beforeResolve 守衛(wèi) (2.5+)。
導(dǎo)航被確認(rèn)。
調(diào)用全局的 afterEach 鉤子。
觸發(fā) DOM 更新。
調(diào)用 beforeRouteEnter 守衛(wèi)中傳給 next 的回調(diào)函數(shù),創(chuàng)建好的組件實(shí)例會(huì)作為回調(diào)函數(shù)的參數(shù)傳入。
顯然,這里使用 beforeRouteLeave 鉤子就能很好地滿足要求:
// 搜索結(jié)果頁(yè)面beforeRouteLeave(to, from, next) {// vuex 存儲(chǔ)操作this.$store.commit("updateRevert", {query: this.queryParam,page: this.pageParam,filter: this.filter,});next(); // 繼續(xù)后續(xù)的導(dǎo)航解析過(guò)程},
加載頁(yè)面時(shí)檢查是否有保存的參數(shù),有的話進(jìn)行相應(yīng)恢復(fù)操作:
// 搜索結(jié)果頁(yè)面mounted() {// 判斷 vuex 中是否有保存的搜索參數(shù)if (this.$store.state.revert) {const revert = this.$store.state.revert;this.queryParam = revert.query;this.pageParam = revert.page; // 可以直接取出整個(gè)對(duì)象// 搜索操作} else {// 沒(méi)有搜索參數(shù)(因?yàn)槲疫@搜索結(jié)果和主頁(yè)是同一個(gè)頁(yè)面,所以有可能只是正常打開(kāi)主頁(yè))}},
結(jié)語(yǔ)
以上是兩種保存頁(yè)面狀態(tài)方式的分享。其中很多選擇是與當(dāng)時(shí)的實(shí)際需求相關(guān)的,因此不一定在所有場(chǎng)景下都是最佳方案。對(duì)于你的具體需求,可能文中的方案可能存在不足,或者有更簡(jiǎn)單的方法;
感謝你的閱讀,如果有什么問(wèn)題,請(qǐng)?jiān)诹粞詤^(qū)給我留言。
學(xué)習(xí)更多技能
請(qǐng)點(diǎn)擊下方公眾號(hào)
![]()

