1. 程式人生 > 其它 >前端 Vue路由返回恢復頁面狀態的實現方案

前端 Vue路由返回恢復頁面狀態的實現方案

需求場景

首頁搜尋內容,點選跳轉至詳情頁,頁面後退返回主頁,保留搜尋結果。

方案:

路由引數;路由守衛

需求描述

在使用 vue 開發前端的時候遇到一個場景:在首頁進行一些資料搜尋,點選搜尋結果進入詳情頁面,瀏覽詳情頁後返回主頁。但這時候之前的搜尋記錄和翻頁就消失了,使用者體驗不好。所以需要在返回後恢復跳轉前的頁面引數狀態。

當然如果條件允許,最簡單的辦法是點選搜尋結果使用新頁面開啟(例如百度那樣)。

但當前需求是一個完整的vue開發的專案,並不是開啟站外地址,而且詳情的內容也不多,使用新頁面不太合適(效能較差而且容易製造巨量標籤頁)。

這裡介紹兩種比較容易實現的解決方案:

  • 方案一:將搜尋引數儲存在路由引數(route.query)中,載入頁面時根據引數搜尋

優點:重新整理不影響;實現簡單
缺點:引數只能是基礎型別、長度受限;路徑看起來比較難看;只對瀏覽器返回有效,手動跳轉回首頁不行

  • 方案二:使用路由守衛鉤子,在離開頁面前本地儲存頁面引數(vuex、Local Storage 等等)

優點:引數型別長度都比較自由;路徑看起來清爽美觀;對任意方式返回主頁都有效
缺點:需要額外進行資料儲存操作,如果使用store模式或vuex則重新整理頁面失效

方案一:路由引數

如果引數不多,並且不介意在路徑後面有一大串引數(流下強迫症的淚水),可以直接把引數放在路由路徑裡

在點選搜尋後,使用 vue router 進行跳轉並傳參:


// 搜尋頁面

search(param) {
  // 其他處理
  this.$router.push({
      name: "Index",
      query: { ...this.queryParam },  // 將物件展開為鍵值
  });
},

這裡要注意 query 傳參和 params 傳參的區別:前者的引數會以 ?k1=v1&k2=v2 的形式續在路徑後面,能直接在位址列中看到,因此不受頁面跳轉、重新整理影響;後者只在第一次跳轉到對應頁面時起作用,再重新整理跳轉就沒有了。

因此這裡要使用 query 傳參。如果把引數按照格式手動寫在 path 中也是可以的,但易讀性和擴充套件性明顯更差,除非只有一兩個簡單引數,否則不推薦。

另外,由於這個引數是要放進路徑裡的,因此只能是基本型別的鍵值對,陣列或物件不能很好地支援。

如果引數簡單,可以將相應的物件展開當做引數(需要保證不同物件中沒有重名鍵),但在跳轉到的搜尋結果頁面中讀取時,就只能逐個屬性的獲取。

// 搜尋結果頁面

mounted() {
  // 區分 $route 和 $router
  if (this.$route.query.type) {
    let type = this.$route.query.type;
    let keyword = this.$route.query.keyword;
    // ...逐一獲取各個引數
    // 進行搜尋操作
  } else {
    // 沒有搜尋引數(因為我這搜尋結果和主頁是同一個頁面,所以有可能只是正常開啟主頁)
  }
},

方案二:本地儲存引數

由於我這想存的引數是三個物件,展開成鍵值取著又太不方便,所以使用了這種方案。

由於專案裡本來也使用了 vuex,就順便存在了 vuex 裡面,根據實際情況存在哪兒都行。

vuex 的缺點是一重新整理就刷沒了,對於搜尋結果這種優化體驗性質的功能影響不大;如果有對應需求可以存在 local storage 裡面。

因為我的需求中有很多中方式改變引數,在改變時儲存引數太麻煩,而且容易出錯或遺漏。因此這裡選擇在路由跳轉之前再統一儲存所需引數。

Vue Router 提供了路由導航守衛系列 API 來實現相應功能,具體包括全域性的前置/解析/後置守衛、路由配置守衛、元件守衛等方式。

所謂”守衛“,其實相當於渲染過程中的”鉤子“,與熟悉的 created, mounted 一樣。

完整的導航解析流程:
1.導航被觸發。
2.在失活的元件裡呼叫 beforeRouteLeave 守衛。
3.呼叫全域性的 beforeEach 守衛。
4.在重用的元件裡呼叫 beforeRouteUpdate 守衛 (2.2+)。
5.在路由配置裡呼叫 beforeEnter。
6.解析非同步路由元件。
7.在被啟用的元件裡呼叫 beforeRouteEnter。
8.呼叫全域性的 beforeResolve 守衛 (2.5+)。
9.導航被確認。
20.呼叫全域性的 afterEach 鉤子。
11.觸發 DOM 更新。
12.呼叫 beforeRouteEnter 守衛中傳給 next 的回撥函式,建立好的元件例項會作為回撥函式的引數傳入。

顯然,這裡使用 beforeRouteLeave 鉤子就能很好地滿足要求:


// 搜尋結果頁面

beforeRouteLeave(to, from, next) {
  // vuex 儲存操作
  this.$store.commit("updateRevert", {
    query: this.queryParam,
    page: this.pageParam,
    filter: this.filter,
  });
  next();  // 繼續後續的導航解析過程
},

載入頁面時檢查是否有儲存的引數,有的話進行相應恢復操作:


// 搜尋結果頁面

mounted() {
  // 判斷 vuex 中是否有儲存的搜尋引數
  if (this.$store.state.revert) {
    const revert = this.$store.state.revert;
    this.queryParam = revert.query;
    this.pageParam = revert.page;  // 可以直接取出整個物件
    // 搜尋操作
  } else {
    // 沒有搜尋引數(因為我這搜尋結果和主頁是同一個頁面,所以有可能只是正常開啟主頁)
  }
},

為了幫助大家更好溫習重點知識、更高效的準備面試,整理了《Vue 面試題總結》電子稿檔案。

Vue面試題

1.vue.js的兩個核心是什麼?
2.vue 的雙向繫結的原理是什麼?
3.vue生命週期鉤子函式有哪些?
4.請問 v-if 和 v-show 有什麼區別?
5.vue常用的修飾符
6.nextTick
7.什麼是vue生命週期
8.資料響應(資料劫持)
9.virtual dom 原理實現
10.Proxy 相比於 defineProperty 的優勢
11.vuex
12.vue中 key 值的作用
13.Vue 元件中 data 為什麼必須是函式?
14.v-for 與 v-if 的優先順序
15.說出至少 4 種 vue 當中的指令和它的用法
16.vue中子元件呼叫父元件的方法
17.vue中父元件呼叫子元件的方法
18.vue頁面級元件之間傳值
19.說說vue的動態元件。
20.keep-alive內建元件的作用

結語

以上是兩種儲存頁面狀態方式的分享。其中很多選擇是與當時的實際需求相關的,因此不一定在所有場景下都是最佳方案。對於你的具體需求,可能文中的方案可能存在不足,或者有更簡單的方法,歡迎評論區留言。

那麼Vue面試題總結完整版的資料小夥伴點選這裡可以獲取。