UI
需求
- 從列表頁的第二頁進入詳情頁,返回時列表頁仍然顯示在第二頁;
- 從列表頁的第二頁進入詳情頁,返回時列表頁的篩選條件仍然存在。
技術選擇
- 使用
vue-router
元件,通過this.$router.push({path: path, query: query});
方式,將頁碼
和選擇條件
作為引數儲存在url中,這種方式在上面的UI設計中是可行的,但是當列表頁中包含tab元件時(分頁元件是公用的),會因為push的因素(因為push會開啟新頁面)導致一些問題(PS:也可能是本人技術能力的原因),未實現。 - 使用
History API
(HTML5開始支援),通過history.replaceState
方式,將頁碼
作為引數儲存在url中,將選擇條件
儲存在history中(尚不清楚資料具體是儲存在哪裡);通過location.hash
方式獲取頁碼
;通過history.state
方式獲取儲存的選擇條件。
具體實現--技術選擇2
開關
為分頁元件新增一個開關(openroute),因為需要灰度上線,萬一有問題,要調整的頁面也只有一個。程式碼如下:
<script>
export default {
props: {
openroute: {
type: Boolean,
default: () => (true)
}
},
}
</script>
複製程式碼
分頁元件中儲存頁碼
和選擇條件
&獲取頁碼
<script>
export default {
methods: {
fetchData(page) {
//請求引數
let params = this.params;
//請求頁碼
let newPage;
//openroute處理
if (this.openroute) {
//為url添上#page
if (page) {
history.replaceState(params.data, document.title, "#" + page);
} else {
if (history.state) {
if (!history.state.key && location.hash && location.hash.split("#") && location.hash.split("#")[1]) {
if (JSON.stringify(history.state) !== JSON.stringify(params.data)) { //選擇條件變更則請求第一頁
history.replaceState(params.data, document.title, "#1");
} else {
history.replaceState(params.data, document.title, "#" + location.hash.split("#")[1]);
}
} else {
history.replaceState(params.data, document.title, "#1");
}
} else {
if (location.hash && location.hash.split("#") && location.hash.split("#")[1]) {
history.replaceState(params.data, document.title, "#" + location.hash.split("#")[1]);
} else {
history.replaceState(params.data, document.title, "#1");
}
}
}
//獲取url後面的#page
if (location.hash && location.hash.split("#") && location.hash.split("#")[1]) {
newPage = Number(location.hash.split("#")[1]);
} else {
newPage = 1;
}
} else {
newPage = page;
}
//請求資料,獲得結果,傳遞給列表頁面
}
}
}
</script>
複製程式碼
列表頁面獲取選擇條件
目前可能是因為框架設計的問題,沒法在請求資料之前通過Object.assign
方式為替換初始變數,所以先這樣處理(笨方法,各位大佬有解決辦法麻煩指導下,謝謝):
<script>
export default {
data() {
return {
form: {
aaa: (history.state && history.state.aaa) ? history.state.aaa : null,
bbb: (history.state && history.state.bbb) ? history.state.bbb : null,
ccc: (history.state && history.state.ccc) ? history.state.ccc : null
},
};
}
};
</script>
複製程式碼
已解決,初始變數不需要動,可以通過以下方式實現:
created(){
//獲取快取的資料
if (history.state) {
Object.assign(this.form, history.state)
if (this.form.key) {
delete this.form.key
}
}
},
複製程式碼
這裡記錄下:之前以為created方法是在分頁元件的watch監聽之後執行的,後來發現被誤導了(因為之前是通過Object.assign(true, this.form, history.state)
方式實現資料賦值的,但是並沒有成功)。下面做個小總結:
Object.assign(true, a, b);”和“Object.assign(a, b);”有什麼區別?
結論:前者:改a不影響b;後者:改a影響b
分析(這篇文章有原始碼分析(求解答:WebStorm中如何關聯原始碼?),很棒):www.cnblogs.com/libin-1/p/6…
FAQ
- 需要使用
history.replaceState
方式是因為:它不會將更改後的url壓到history棧中,所以不會增加回退和前進的操作步數; - 使用
history.replaceState
方式,可儲存的state大小不能操作640k; - 可能存在瀏覽器相容性問題,請從此處查閱:caniuse.com/#feat=histo…。
Demo Or Source
因為是公司專案,所以目前沒有Demo或原始碼