使用ajax和window.history.pushState无刷新改变页面内容和地址栏URL

hanliuxinming 2015-07-18

后退时关闭当前页面

<scripttype="text/javascript">

jQuery(document).ready(function($){

if(window.history&&window.history.pushState){

$(window).on('popstate',function(){

WeixinJSBridge.call('closeWindow');

/**

window.opener=null;

window.open('','_self');

window.close();

*/

returnfalse;

});

window.history.pushState('forward',null,'Wx.AuthSuccess.jdp');

//window.history.pushState('forward',null,'baidu.com');

//window.location.href="www.baidu.com";

//WeixinJSBridge.call('closeWindow');

}

});

</script>

2、替换当前历史记录点

window.history.replaceState和window.history.pushState类似,不同之处在于replaceState不会在window.history里新增历史记录点,其效果类似于window.location.replace(url),都是不会在历史记录点里新增一个记录点的。当你为了响应用户的某些操作,而要更新当前历史记录条目的状态对象或URL时,使用replaceState()方法会特别合适。

3、监听历史记录点

监听历史记录点,直观的可认为是监听URL的变化,但会忽略URL的hash部分,监听URL的hash部分,HTML5有新的API为onhashchange,我的博客里也有说到该方法和跨浏览器的兼容解决方案。可以通过window.onpopstate来监听url的变化,并且可以获取存储在该历史记录点的状态对象,也就是上文说到的json对象,如:

//当前的url为:http://www.qingdou.me/post-1.html

window.onpopstate=function()

{

//获得存储在该历史记录点的json对象

varjson=window.history.state;

//点击一次回退到:http://www.qingdou.me/index.html

//获得的json为null

//再点击一次前进到:http://www.qingdou.me/post-1.html

//获得json为{time:1369647895656}

}

值得注意的是:javascript脚本执行window.history.pushState和window.history.replaceState不会触发onpopstate事件。

还有一点注意的是,谷歌浏览器和火狐浏览器在页面第一次打开的反应是不同的,谷歌浏览器奇怪的是回触发onpopstate事件,而火狐浏览器则不会。

======================================================================

QAteam通过Tealeaf和Avicode检测到application有很多的500errrors,因此这2周几乎都在解决这个问题。通过reproduce这些各种不同的错误,几乎可以把原因归结在浏览器的后退按钮(pressingbackbutton)和键盘的后退键(backspace),和leader交流下,觉得有必要阻止页面后退。

当然,相关的文章到处走势,其实就是一篇文章都是转来转去的.基本上是3个solution:

1).设置网页过期(服务器端)

2).javascript:window.history(客户端)

3).对于键盘的backspace.通过window.event来过滤,当然要考虑的是对于Input控件,要保持删除的功能。

<scripttype="text/javascript">

functionbackspace(){

if(event.keyCode==8&&event.srcElement.tagName!="INPUT"&&event.srcElement.type!="text")

event.returnValue=false;

}

if(navigator.appName=="MicrosoftInternetExplorer"){

window.history.forward(1);

}

else//ifitisMozillathan

{

window.history.forward(-1);

}

</script>

下面是我的尝试:

1)先来说对于,网页过期的:

网页一旦过期,意味着每次页面的刷新,需要重新从服务器端获取所有的网页资源。这时候如果通过浏览器的后退按钮,进行后退,就会reload整个页面,相当于一个getrequest.因此对于相应页面会执行OnLoad事件,以及OnLoadCompleted事件

若在OnLoadCompleted事件页面没能获取到所需要的资源,将会显示网页已过期的错误。但是无论讲*****怎样添加到页面中,都不能重现网页已过期的错误,

2)对于页面可客户端的OnLoad执行脚本:Windows.History.Forward(1),对于这个方法别人说不完美,但没有说处理理由。我相说的是,对于直接点击后腿按钮的情况,Window.History.Forward(1)几乎可以Cover大多数场景,只是一个奇怪的事情当所有的后退经过一个页面的时候,就会停止,不会继续forward到原来页面。原以为这就是我们的解决500errors的钥匙,但是一次不经意的聊天,让我们想起了,如果不是点击后腿按钮,而是选择HIstoryList中网页,又该如何去处理?为了解决这一问题,我有2个想法

a)获取选择HistoryList中页面的index,然后Windows.History.Froward(index),查阅资料,最后在msdn上看到的解释是,处于安全的因素microsoft不会暴露Window.history对象中url实际地址和Index,也就是说无法得到HistoryList网页的具体信息。

b)记录后退之前页面的URL,然后直接用Windows.Location.Href,记录后退之前的url这个不难,<%=%><%#%>,均可做到,但是问题来了,如何区分网页的getreque是由于后退造成的,似乎有一个无解!

不过在探索a,b的时候,想到2个问题

1)关于Windows..history.forward();如果windows.historyList中只有5个页面,但是我把Windows..history.forward(100),结果会是如何。

2)如果我在historylist选择一个距离当前页面距离不是1的页面Windows..history.forward(1),会如何工作?

解释:

1)其实Windows..history.forward(100)和Windows..history.forward(1)的效果是一样的.

那Windows..history.forward(1),究竟是如何工作的,通过httpwatch

wps_clip_image-11801

可以看到,Windows..history.forward(1),总是会将windows.history.list里买你的所有页面走完,直到页面再也不能往前,对于windows.history.list.length=5的时候,无论在哪个页面发起history,forward(1),都会走到当前页面。因此是可以很好地阻止页面后退,缺点是带来了很多的额外的httprequest,因为需要一个页面一个页面后退。

另外一个奇怪的问题:在我们的一个application里面我发现,windows.history.forward(1),会走到某个页面,停止。以至于在那个页面之后的页面,就无法实现组织后退的功能。我偶然发现对于windows.history.forward(1)页面居然会执行OnInit,Onload,OnloadComplete这些事件,我很费解,为什么windows.history.forward会触发服务器端事件呢,然来是因为在基类里面设置了缓存过期,这样每次需要从server上取页面资源。

因此页面过期和windows.history.forward是不可以一起使用的

===============================================================

按微信产品部副总经理张颖“每一个公众号都是一个APP”的说法,我们确实可以利用微信内置浏览器访问为公众号设计WebApp单页应用,以使得客户在访问公众号时有近似原生App的体验,不过目前这样的公众号很少,原因除了使用javascript开发单页应用的难度比开发一般的Web页面难度更高一些,更重要的一点是使用微信内置浏览器访问Web页面时,Android用户一按物理返回键就回到微信界面,而Android用户按物理返回键的习惯预期是回到上一页,这样就使得微信公众号的WebApp客户体验非常差。

有什么方法改变这一点么?最理想的解决办法是微信自己接管用户按物理返回键这个事件,然后类似像getNetworkType一样提供javascript事件给开发者使用。不过很遗憾,腾讯目前没有提供这个事件,而且看样子将来也不打算提供。

这个问题不是大问题,但如果不解决会影响Android用户的客户体验。幸运的是,我找到了解决办法,方法就是利用javascriptwindowhistory来解决。

由于安全原因javascript不允许修改history里已有的url链接,但可以使用pushState方法往history里增加url链接,并且提供popstate事件监测从history栈里弹出url。我们可以利用这一点,在WebApp加载主界面后先往history里压入“#”链接,然后监听popstate事件,在Android手机的浏览器,按下物理返回键默认的操作是执行window.history.back(),此时将触发popstate事件。收到popstate事件时代码显示“再按一次退出程序”div顶层标签,此时history栈已经为空,如用户再次按下物理返回键将执行默认操作回到微信。接着,我们要设定一个定时器,在指定的时间(比如2秒)后如用户没有再次按下物理返回键将再次往history里压入“#”链接,并隐藏“再按一次退出程序”div顶层标签,等待用户下一次按下物理返回键。

pushHistory();

setTimeout(function(){

window.addEventListener("popstate",function(e){

showBox("再按一次退出程序",2000,function(){

pushHistory();

});

},false);

08

},300);

functionpushHistory(){

varstate={

title:"title",

url:"#"

};

window.history.pushState(state,"title","#");

}

functionshowBox(msg,timeOut,onTimeOut){

if(typeofalertBoxDiv==="undefined"){

alertBoxDiv=$("<div/>").addClass("alert-boxhide").append($("<div/>").addClass("labellabel-primary")).appendTo($("body"));

}

alertBoxDiv.children(".label").html(msg);

alertBoxDiv.removeClass("hide");

if(typeoftimeOut==="undefined")timeOut=2000;

setTimeout(function(){

alertBoxDiv.addClass("hide");

if(typeofonTimeOut!=="undefined")onTimeOut();

},timeOut);

}

监听popstate事件的代码稍作修改就可以用于任意控制单页应用中javascript生成的任意动态页面的跳转,此方法已经在微信公众号WebApp中使用,可在微信中搜索“myfunds”公众号关注体验。这个方法也可以用于微信公众号之外的WebApp,链接就不发了,免得CSDN又要审查。

window.history.pushState('forward',null,'Wx.deputyDiaryList.jdp?t='+newDate().getTime());

1.在一个页面中添加多少历史记录,后退,只要没有页面的转换,就不会跳转到页面;(A--B页面。再B页面pushState多少记录,后退时这些记录URL都不会刷新该URL的页面;只有在B到A的时候才会触发)

2.

微信中只要按后退键就触发$(window).on('popstate',function(){};

浏览器中:

流程是:A->B,B原URL--新增一个新URL显示在地址栏--当按后退按钮时地址栏先退回原URL--

--退回A最后的RUL,这时才会触发$(window).on('popstate',function(){}。

history.replaceState

流程是:A->B,B原URL--替换一个新URL显示在地址栏--当后退时则直接退回新URL地址页面

(好像)并不触发$(window).on('popstate',function(){};

可能是因为地址栏地址都一样导致。。

相关推荐