前言
這篇文章主要講解決思路,不對各種概念進行過多講解。
問題描述
開發微信H5頁面的時候,在Ios微信內置瀏覽器中點擊返回按鈕返回上一頁時,上一頁面不會被刷新。
在瀏覽器緩存機制中,在返回上一頁的操作中, html/js/css/接口等動靜態資源不會重新請求,但是js會重新加載。但在Ios微信頁面中js也會保存上一頁面最后執行的狀態,不會重新執行js。使用這種模式緩存機制可以加快渲染速度,但是部分數據需要經常展示和編輯的情況下回導致不同步。比如“詳情頁”跳轉到“編輯頁”,在“編輯頁”中修改數據后返回到詳情頁中,“詳情頁”數據展示並未進行同步修改。
產生原因
這里提到一個概念,瀏覽器前進/后退緩存,(Backward/Forward Cache,BF Cache),當然也有人叫disk Cache。BF Cache 是一種瀏覽器優化,html標准並未指定其如何進行緩存,因此緩存行為是各瀏覽器實現不盡相同。由於不是Http緩存,所以通過頭文件緩存設置no-cache是無效的。當然也不能以Http緩存機制來理解BF Cache。
解決思路
從網上看了幾種比較常見的解決思路,下面簡單講解。
設置瀏覽歷史當前記錄
history.replaceState方法的參數與pushState方法一模一樣,區別是它修改瀏覽歷史中當前紀錄。
var href = location.href;
var time = new Date().getTime(); href += href.indexOf('?') > -1 ? ('&time='+time) : ('?time=' + time); history.replaceState({}, "title", href); // 比如當前頁面地址為http://www.a.com; 通過history.replaceState修改后當前地址會變為http://www.a.com?time=xxx
網上這種解決思路比較多,實際情況中並不可行。
原因:Ios微信中調整到下一頁面后並未將上一頁面修改的url保持在歷史記錄中,以代碼為例,返回上一頁並未返回到http://www.a.com?time=xxx , 而是返回到 http://www.a.com 中。
通過時間差來判斷是否需要重置
var prev = parseInt(new Date().getTime() / 1000); var now = prev; window.setInterval(function() { now = parseInt(new Date().getTime() / 1000); // 當前步驟與上一步驟時間差超過1秒,表示頁面已經跳轉過 // 時間差需要與間隔時間相對應 if (now - prev > 1) { location.reload(); } else { prev = now; } // 間隔時間設置為1秒 }, 1000);
原理:通過判斷當前步驟與上一步驟的時間差來判斷是否需要更新
缺點:間隔輪詢時間差長度設置為多久比較好,不好掌控; 通過setInterval設置的間隔時間差並不是很精確; 並且兩個頁面之間的反復切換速度非常迅速的情況下也許會出現監測不到的現象。
通過localStorage控制是否需要刷新
localStorage.setItem("need-refresh", true); $(function () { var needRefresh = localStorage.getItem("need-refresh"); if(needRefresh) { localStorage.removeItem("need-refresh"); location.reload(); } });
原理:通過獲取瀏覽器保存的key來決定頁面是否需要刷新
缺點:當頁面關閉再重新打開時,key(也就是代碼中的need-refresh)key值為true,會導致頁面加載兩次,造成重復渲染
廣州品牌設計公司https://www.houdianzi.com
通過pageshow事件決定是否需要刷新頁面
window.addEventListener('pageshow', function(e) { // 通過persisted屬性判斷是否存在 BF Cache if (e.persisted) { location.reload(); } });
原理:pageShow事件在頁面顯示即會觸發,無論頁面是否來自BF Cache。通過檢測persisted屬性即可判斷是否存在 BF Cache 行為。
優點:大部分瀏覽器都支持pageShow方法與persisted屬性,並且需要的代碼量只需要短短4行即可。
缺點:每種瀏覽器中BF Cache的機制是不同的,部分瀏覽器中的Bf Cache還是會重新執行js代碼,會造成重復渲染效果。當然這篇文章中我們只考慮Ios中的微信頁面, 所以是不存在問題。