標籤:exp 恢複 window The 並且 bfc 儲存 原因 ever
70313112
一些瀏覽器中返回按鈕是直接使用緩衝的,不會執行任何js代碼,例如, 在提交的時候將按鈕設定為loading狀態,如果在提交成功後沒有對按鈕進行處理,那麼返回後按鈕依然是loading狀態,這就很尷尬了。
原因:部分瀏覽器在後退時不會觸發onload事件,這是HTML5世代瀏覽器新增的特性之一——Back-Forward Cache(簡稱bfcache)
什麼是bfcache
《JavaScript進階程式設計》有提及bfcache:
bfcache,即back-forward cache,可稱為“往返緩衝”,可以在使用者使用瀏覽器的“後退”和“前進”按鈕時加快頁面的轉換速度。這個緩衝不僅儲存頁面資料,
還儲存了DOM和JS的狀態,實際上是將整個頁面都儲存在記憶體裡。如果頁面位於bfcache中,那麼再次開啟該頁面就不會觸發onload事件
pageshow事件
這個事件在頁面顯示時觸發,無論頁面是否來自bfcache。在重新載入的頁面中,pageshow會在load事件觸發後觸發;
而對於bfcache中的頁面,pageshow會在頁面狀態完全恢複的那一刻觸發。
pagehide事件
該事件會在瀏覽器卸載頁面的時候觸發,而且是在unload事件之前觸發。
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
12345 |
window.addEventListener(‘pageshow‘, function( e ){if (e.persisted) {window.location.reload()}}) |
Safari、UC、qq瀏覽器測試通過。但是UC、qq瀏覽器會先閃過bfcache中的頁面,因為pageshow是在load事件觸發之後才觸發的。browser依然會保留紅色,我認為是因為browser回到上頁時不觸發任何事件。
JS監聽pagehide事件阻止頁面進入bfcache
123456789 |
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部分加入如下的禁用緩衝設定:
1234567 |
<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。需要頁面本身有禁用緩衝的配置。
12345678910111213141516171819 |
<!-- 安卓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_VERsessionStorage.PAGEVERSION = REMOTE_VER;}}</script><!-- 安卓webview 後退強制重新整理解決方案 END --> |
總結
PC瀏覽器,設定禁用頁面緩衝header即可實現後退重新整理
支援bfcache/page cache的移動端瀏覽器,JS監聽pageshow/pagehide,在檢測到後退時強制重新整理
在前2個方案都不work的情況下,可以在HTML中寫入服務端頁面產生版本號碼,與本機存放區中的版本號碼對比判斷是否發生了後退並使用緩衝中的頁面
解決手機上頁面返回但是頁面js沒有重新整理的痛點