監控頁面後退前進,瀏覽器文件載入事件之pageshow、pagehide

milo_藍色大飛機發表於2017-05-12

首先說說為什麼會學習這個pageshow的起因吧,專案中一個表單頁面,需得填寫驗證碼,填寫驗證碼後提交,由於使用的form直接提交,沒有使用AJAX,所以,在出現驗證碼填寫錯誤的時候,就會跳轉到錯誤提示頁,3秒倒數計時後使用history.back(-1)的方式返回上一頁,這也就出現了一個問題,使用history.back(-1)進行後退之後,圖形驗證碼已過期,但是卻沒有重新整理,這樣就導致使用者重複多次填寫驗證碼,影響使用者體驗;

發現了問題,首先分析一下唄:

*瀏覽器前進、後退使用機制

*如何在前進、後退後執行js

一. 問題一:瀏覽器前進、後退使用機制

使用者點選瀏覽器工具欄中的後退按鈕,或者移動裝置上的返回鍵時,或者JS執行history.go(-1);時,瀏覽器會在當前視窗“開啟”歷史紀錄中的前一個頁面。不同的瀏覽器在“開啟”前一個頁面的表現上並不統一,這和瀏覽器的實現以及頁面本身的設定都有關係。在瀏覽器中,“後退到前一個頁面”意味著:前一個頁面的html/js/css等靜態資源的請求(甚至是ajax動態介面請求)根本不會重新傳送,直接使用快取的響應,而不管這些靜態資源響應的快取策略是否被設定了禁用狀態。
各個瀏覽器測試demo:先點選按鈕使其變色,然後調整至百度,再後退回來檢視:

function dispLog(msg) {
  var d = new Date();
  $("<li />").text(d.toISOString().substr(14, 9) + " " + msg)
  .appendTo("#dvDisp");
}

window.addEventListener('load', function(event) {
    dispLog("Load Event  ");
})
//引入了jq監聽ready事件做比較
$(window).ready(function () {
    dispLog("Ready Event");
 });
$("#btnSetColor").click(function () {
    $("#btnSetColor").css("background", "red");
})
window.addEventListener('pageshow', function(event) {
    dispLog("PageShow Event  " + event.persisted);
    //使用event.persisted判斷頁面是否使用bfcache,值為true或false;  注:如果使用jq繫結事件,需使用event.originalEvent.persisted;
})
window.addEventListener('pagehide', function(event) {
    dispLog("Load Event  " + event.persisted);
})
            

線上測試地址: pageshow
移動端測試demo:
監控頁面後退前進,瀏覽器文件載入事件之pageshow、pagehide

本人的測試結果:

1.PC端瀏覽器

瀏覽器 首次進入頁面 點選按鈕,再跳轉至百度,再後退
chrome 58.0.3029.9 執行ready→load→pageshow 重新執行ready→load→pageshow 按鈕顏色消失 頁面相當於重新重新整理了
IE789 執行ready→load 重新執行ready→load 按鈕顏色消失 頁面相當於重新重新整理了 pageshow不相容IE10-
firefox 53.0.2 執行ready→load→pageshow 重新執行ready→load→pageshow 按鈕顏色消失 頁面相當於重新重新整理了
QQBrowser 9.6 執行ready→load→pageshow 重新執行ready→load→pageshow 按鈕顏色消失 頁面相當於重新重新整理了
360Browser 8.1.1.254 執行ready→load→pageshow 重新執行ready→load→pageshow 按鈕顏色消失 頁面相當於重新重新整理了
Safari 5.1.7(沒mac,用的很早版本的windowsafari) 執行ready→load→pageshow 新增→pagehide→pageshow 按鈕顏色紅色 引用了快取(event.persisted == true)

safari

PC端總結:現代的PC瀏覽器後退後基本都是重新執行load,對頁面重新進行一次載入,所以不會有上面的驗證碼不重新整理的問題,由於窮屌沒有mac電腦,只下載了很久之前的safari瀏覽器,測試結果只做參考;

2.移動端瀏覽器 (安卓端),測試機型小米5S,iphone4s

瀏覽器 首次進入頁面 點選按鈕,再跳轉至百度,再後退
UCBrowser 執行ready→load→pageshow 新增→pagehide→pageshow 按鈕顏色紅色 引用了快取(event.persisted == true)
QQBrowser 執行ready→load→pageshow 新增→pagehide→pageshow 按鈕顏色紅色 引用了快取(event.persisted == true)
QQ內建瀏覽器 執行ready→load→pageshow 重新執行ready→load→pageshow 按鈕顏色消失 頁面相當於重新重新整理了
360Browser 執行ready→load→pageshow 無觸發事件,按鈕顏色紅色 引用了快取(event.persisted == true)
chorme 執行ready→load→pageshow 重新執行ready→load→pageshow 按鈕顏色消失 頁面相當於重新重新整理了
微信內建 執行ready→load→pageshow 重新執行ready→load→pageshow 按鈕顏色消失 頁面相當於重新重新整理了
小米自帶 執行ready→load→pageshow 無觸發事件,按鈕顏色紅色 引用了快取(event.persisted == true)
safari 執行ready→load→pageshow 新增→pagehide→pageshow 按鈕顏色紅色 引用了快取(event.persisted == true)

效果圖:選了三種型別各一個

重新整理頁面型別 不重新整理不執行型別
chrome測試頁面效果 監控頁面後退前進,瀏覽器文件載入事件之pageshow、pagehide
不重新整理執行事件型別(理想型)
監控頁面後退前進,瀏覽器文件載入事件之pageshow、pagehide
這就很頭疼了,三種不同的情況,對於chrome和UC型別的情況,對於我的回退驗證碼重新整理問題,很容易處理,最麻煩的360型別的,但是。。。發現了更蛋疼的情況了:
後退不reload,不執行pageshow的瀏覽器在公司的一個專案中,居然能實現後退重新整理。。。。 同一段測試程式碼,發到專案伺服器上,是可以後退重新整理,
但是,在我自己的虛擬主機中卻不行,南蝶?是因為請求頭部設定嗎??? 先挖個坑在這,等我去好好了解一下PHP 和 http請求 再回來戰!

二、如何在前進、後退後執行js

百度、google類似問題,最多的解決方法:pageshow;

Firefox和Opera有一個新特性,名叫“往返快取”(back-forward cache,或bfcache),可以在使用者使用瀏覽器的“後退”和“前進”按鈕時加快頁面的轉換速度。
這個快取中不僅儲存著頁面資料,還儲存了DOM和JavaScript的狀態;實際上是將整個頁面都儲存在了記憶體裡。
如果頁面位於bfcache中,那麼再次開啟該頁面就不會觸發load事件。
儘管由於記憶體中儲存了整個頁面的狀態,不觸發load事件也不應該會導致什麼問題,但為了更形象地說明bfcache的行為,Firefox還是提供了一些新事件。
第一個事件就是pageshow,這個事件在頁面顯示時觸發,無論頁面是否來自bfcache。在重新載入頁面中,pageshow會在load事件觸發後觸發;
而對於bfcache中的頁面,pageshow會在頁面狀態完全恢復的那一刻觸發。另外要注意的是,雖然這個事件的目標是document,但必須將其事件處理程式新增到window。

相關文章