解決手機上頁面返回可是頁面js沒有刷新的痛點

https://blog.csdn.net/playboyanta123/article/details/70313112javascript

一些瀏覽器中返回按鈕是直接使用緩存的,不會執行任何js代碼,例如, 在提交的時候將按鈕設置爲loading狀態,若是在提交成功後沒有對按鈕進行處理,那麼返回後按鈕依然是loading狀態,這就很尷尬了尷尬html

緣由:部分瀏覽器在後退時不會觸發onload事件,這是HTML5世代瀏覽器新增的特性之一——Back-Forward Cache(簡稱bfcache)java

什麼是bfcacheweb

《JavaScript高級程序設計》有說起bfcache:瀏覽器

bfcache,即back-forward cache,可稱爲「往返緩存」,能夠在用戶使用瀏覽器的「後退」和「前進」按鈕時加快頁面的轉換速度。這個緩存不只保存頁面數據,緩存

還保存了DOM和JS的狀態,其實是將整個頁面都保存在內存裏。若是頁面位於bfcache中,那麼再次打開該頁面就不會觸發onload事件網絡

pageshow事件

這個事件在頁面顯示時觸發,不管頁面是否來自bfcache。在從新加載的頁面中,pageshow會在load事件觸發後觸發;session

而對於bfcache中的頁面,pageshow會在頁面狀態徹底恢復的那一刻觸發。app

pagehide事件

該事件會在瀏覽器卸載頁面的時候觸發,並且是在unload事件以前觸發。jsp

persisted屬性

pageshow事件和pagehide事件的event對象還包含一個名爲persisted的布爾值屬性。

  • 對於pageshow事件,若是頁面是從bfcache中加載的,則這個屬性的值爲true;不然,這個屬性的值爲false。
  • 對於pagehide事件,若是頁面在卸載以後被保存在bfcache中,則這個屬性的值爲true;不然,這個屬性的值爲false。

不一樣的瀏覽器在瀏覽器會在當前窗口「打開」歷史紀錄中的前一個頁面的表現上並不統一,這和瀏覽器的實現以及頁面自己的設置都有關係。

 

解決方案

 

Firefox的開發者文檔中提供了一些思路:

  • 頁面監聽了 unload 或者 beforeunload 事件;
  • 頁面設置了 「cache-control: no-store」.
  • 網站使用 HTTPS 同時頁面至少知足如下一個條件:
    • 「Cache-Control: no-cache」
    • 「Pragma: no-cache」
    • 設置請求頭 「Expires: 0」 或者 「Expires」 的值爲 「Date」 以前的值 (除非 「Cache-Control: max-age=」 也被設置了);
  • 頁面在用戶前進後退的時候尚未徹底加載完或者它有正在進行的網絡請求,好比 XMLHttpRequest;
  • 頁面正在進行IndexedDB操做;
  • 頂層的頁面包含有frame,而且這些frame因爲這裏列的任何一條緣由而不能被緩存;
  • 頁面在一個frame內,而且用戶在這個frame內跳轉到了一個新的網頁,這裏將被緩存的是新載入的網頁

JS監聽pageshow事件阻止頁面進入bfcache

 
    
1
2
3
4
5
 
    
window.addEventListener('pageshow', function( e ){
if (e.persisted) {
window.location.reload()
}
})

 

Safari、UC、qq瀏覽器測試經過。可是UC、qq瀏覽器會先閃過bfcache中的頁面,由於pageshow是在load事件觸發以後才觸發的。browser依然會保留紅色,我認爲是由於browser回到上頁時不觸發任何事件。

JS監聽pagehide事件阻止頁面進入bfcache

 
    
1
2
3
4
5
6
7
8
9
 
    
window.addEventListener('pagehide', function(e) {
var $body = $(document.body);
$body.children().remove();
 
// 要等到回調函數完成,用戶按返回才執行script標籤的代碼
setTimeout( function() {
$body.append( "<script type='text/javascript'>window.location.reload();<\/script>");
});
});

 

Safari、UC、qq瀏覽器測試經過。browser依然會保留紅色,我認爲是由於browser回到上頁時不觸發任何事件。

給響應添加Cache-Control的header

代碼示例以下:
在jsp模板的header部分加入以下的禁用緩存設置:

 
    
1
2
3
4
5
6
7
 
    
<head>
<%
response.setHeader("Cache-Control","no-cache,no-store,must-revalidate");
response.setHeader("Expires", "0");
response.setHeader("Pragma","no-cache");
%>
</head>

 

安卓webview cache的解決方案

該方案的前提是瀏覽器在向server請求頁面時,每次都用jsp從新生成html。須要頁面自己有禁用緩存的配置。

 
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
    
<!-- 安卓webview 後退強制刷新解決方案 START -->
<jsp:useBean id="now" class="java.util.Date" />
<input type="hidden" id="SERVER_TIME" value="${now.getTime()}"/>
<script>
//每次webview從新打開H5首頁,就把server time記錄本地存儲
var SERVER_TIME = document.getElementById("SERVER_TIME");
var REMOTE_VER = SERVER_TIME && SERVER_TIME.value;
if(REMOTE_VER){
var LOCAL_VER = sessionStorage && sessionStorage.PAGEVERSION;
if(LOCAL_VER && parseInt(LOCAL_VER) >= parseInt(REMOTE_VER)){
//說明html是從本地緩存中讀取的
location.reload( true);
} else{
//說明html是從server端從新生成的,更新LOCAL_VER
sessionStorage.PAGEVERSION = REMOTE_VER;
}
}
</script>
<!-- 安卓webview 後退強制刷新解決方案 END -->

 

總結

  1. PC瀏覽器,設置禁用頁面緩存header便可實現後退刷新

  2. 支持bfcache/page cache的移動端瀏覽器,JS監聽pageshow/pagehide,在檢測到後退時強制刷新

  3. 在前2個方案都不work的狀況下,能夠在HTML中寫入服務端頁面生成版本號,與本地存儲中的版本號對比判斷是否發生了後退並使用緩存中的頁面

相關文章
相關標籤/搜索