首先說說為什么會學習這個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:

本人的測試結果:
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) |

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和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。



