浏览器返回按钮不会触发onLoad事件

  最近在作一个移动端项目,发现移动端某些返回和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

相关文章
相关标签/搜索