最近在作一個移動端項目,發現移動端某些返回和PC端是有差別的, 好比ios中返回按鈕是直接使用緩存的, 不會執行任何js代碼, 這個問題很蛋疼, 例如, 在提交的時候將按鈕設置爲loading狀態, 若是在提交成功後沒有對按鈕進行處理, 那麼返回後按鈕依然是loading狀態, 這種體驗不好, 以下圖:css
此問題是因爲某些瀏覽器在back的時候是直接使用的以前的視圖,頁面沒有進行從新加載而致使的,在網上找了些資料, 發現這是H5的一些新特性Back-Forward Cache(簡稱bfcache) ,普通瀏覽器在back時,若是不是指定Cache-Control、Expires等方法強制停用Cache時,那麼通常狀況下瀏覽器大多數都會直接讀取本地的緩存, 減小請求和網絡傳輸的成本, 增長瀏覽的順從度, 但Cache僅限於靜態文件, 瀏覽器仍是得從新加載html, 從新執行腳本,渲染DOM, 而bfcache則不一樣, 是直接讀取緩存裏面的html,節省了從新請求頁面的時間, 既然是讀取緩存的html頁面, 那麼執行頁面的onload事件進行初始化, 會影響本來因用戶操做而改變的狀態, 因此瀏覽器在back時是不會觸發onload事件.html
這個時候就會產生上面的問題, 有些業務在返回時是須要從新加載的, 因而H5新增了兩個事件onpageshow和onpagehide, 分別是進入網頁和離開的時候觸發, 即便是用瀏覽器的前進/後退也會觸發這兩個事件.jquery
1 <!DOCTYPE html> 2 3 <html> 4 <head> 5 <title>Page Events</title> 6 <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.js"></script> 7 <script> 8 function dispLog(msg) { 9 var d = new Date(); 10 $("<li />").text(d.toISOString().substr(14, 9) + " " + msg) 11 .appendTo("#dvDisp"); 12 13 } 14 $(window).load(function () { 15 dispLog("Load Event"); 16 }).ready(function () { 17 dispLog("Ready Event"); 18 $("#btnSetColor").click(function () { 19 $("a").css("color", "red"); 20 }); 21 }).bind("pageshow", function () { 22 dispLog("PageShow Event"); 23 }).bind("pagehide", function () { 24 dispLog("PageHide Event"); 25 }); 26 </script> 27 </head> 28 <body> 29 <a href="test1.html">前往其它頁面</a> 30 <input type="button" id="btnSetColor" value="變色" /> 31 <ul id="dvDisp"></ul> 32 </body> 33 </html>
頁面很簡單, 綁定onload, ready,onpageshow,onpagehide四個事件, 觸發事件相應的文本會顯示在頁面上, 另外這裏有個鏈接可跳轉到其它網頁,便於測試back, button事件會改變鏈接的顏色, 便於back時檢查顏色是否保留,判斷是否有bfcache.ios
測試步驟打開test.html, 點擊變色按鈕, 再點擊"前往其它頁面", 而後在test1.html點擊back按鈕回到test.html. 在幾回測試後, 大體的測試結果以下:ajax
IE9
打開頁面或則back時都會觸發Ready/Load事件, 紅色未保留, 無bfcache.
IE10 (Windows 8 Release Preview)
打開頁面或則back時都會觸發Ready/Load事件, 紅色未保留, 無bfcache.
Chrome 21.0.1180.6
打開頁面或則back時都會觸發Ready/Load/PageShow事件, 紅色未保留, 無bfcache.
Firefox 15.0
打開頁面或則back時都會觸發Ready/Load/PageShow事件,點擊[前往其它網頁]會觸發PageHide, [back]時會觸發PageShow, 紅色被保留, 有bfcache.
Safari 5.1.5
打開頁面或則back時都會觸發Ready/Load/PageShow事件,點擊[前往其它網頁]會觸發PageHide, [back]時會觸發PageShow, 紅色被保留, 有bfcache.
Safari on iPad (iOS 5.1.1)
打開頁面或則back時都會觸發Ready/Load/PageShow事件,點擊[前往其它網頁]會觸發PageHide, [back]時會觸發PageShow, 紅色被保留, 有bfcache.
Opera 12.00
打開頁面或則back時都會觸發Ready/Load事件, [back]時會觸發PageShow, 紅色被保留, 有bfcache但不會觸發PageShow事件.
總結: Firefox和Safari會bfcache, back時不會觸發load, ready事件, 只會觸發onpageshow, 而chrome雖然支持onpageshow, 可是back時同樣都會觸發load,ready事件, opera最操蛋, back時會bfcache,可是不觸發onpageshow事件.chrome
回到上面的問題, 如何解決bfcache時ready在back時不執行的問題呢?瀏覽器
起初是想新增一個$.pageshow(), 若瀏覽器支持, 將業務代碼放在onpageshow事件裏面處理, 不然用ready處理, 以下:緩存
1 $.pageshow = function (fn) { 2 if (typeof window.onpageshow == "undefined") 3 $(document).ready(fn); 4 else 5 $(window).bind("pageshow", fn); 6 }; 7 $.pageshow(function () { 8 alert("Page Show"); 9 alert(typeof window.onpageshow == "undefined") 10 });
很艹蛋啊, 這個方法只能解決Firefox、Safaer上的問題, 可是在Opera上就沒什麼效果.網絡
還好在MDC的文檔上找到一點思路, Firefox在某些條件下禁用bfcache:app
There are instances in which Firefox doesn’t cache pages. Below are some common programmatic reasons that a page is not cached: the page uses an unload or beforeunload handler; the page sets "cache-control: no-store". the site is HTTPS and page sets at least one of: "Cache-Control: no-cache" "Pragma: no-cache" with "Expires: 0" or "Expires" with a date value in the past relative to the value of the "Date" header (unless "Cache-Control: max-age=" is also specified); the page is not completely loaded when the user navigates away from it or has pending network requests for other reasons (e.g. XMLHttpRequest)); the page has running IndexedDB transactions; the top-level page contains frames (e.g. <iframe> ) that are not cacheable for any of the reasons listed here; the page is in a frame and the user loads a new page within that frame (in this case, when the user navigates away from the page, the content that was last loaded into the frames is what is cached).
想了下若是Firefox能夠這樣, Safari和Chrome應該也能夠, 因而找到一個很是簡單的方法來解決這個問題, 而且兼容Firefox、Safari、Opera, 只要在頁面中加入下面的代碼:
$(window).unload(function () { });
通過測試, 頁面上一點綁定unload事件, Firefox/Safari/Opera等瀏覽器變會認爲該頁面不須要bfcache, 迴歸到傳統的Cache模式, 這樣就能解決back時不觸發onload, ready等事件帶來的問題了.
下面有兩個鏈接, 不過解決問題的思路都差很少.
http://stackoverflow.com/questions/11979156/mobile-safari-back-button
http://stackoverflow.com/questions/24046/the-safari-back-button-problem