近来在处理浏览器禁刷功能时,用到一个新属性:history.pushState();

官方解释如下:

history.pushState()方法和history.replaceState()方法,它们允许你逐条地添加和修改历史记录条目。这些方法可以协同window.onpopstate事件一起工作。

使用 history.pushState() 会改变 referrer 的值,而在你调用方法后创建的XMLHttpRequest对象会在 HTTP 请求头中使用这个值。referrer的值则是创建XMLHttpRequest对象时所处的窗口的URL。


首先附上一个实例功能:

//防止浏览器后退功能$(document).ready(function(e){varurl=window.location.href;varlast=url.substring(url.lastIndexOf("/"));if(window.history&&window.history.pushState){$(window).on('popstate',function(){//在IE中必须得有这两行window.history.pushState('forward',null,url);window.history.forward(1);});}//屏蔽鼠标右键$(document).bind("contextmenu",function(e){returnfalse;});//屏蔽f5和回车功能$(document).bind("keydown",function(e){if(event.keyCode==116){event.keyCode=0;event.cancelBubble=true;returnfalse;}});});


以及附上【pushState】和【replaceState】的基础语法区别:


history.pushState(state, title, url)

将当前URL和history.state加入到history中,并用新的state和URL替换当前。

不会造成页面刷新。

state:与要跳转到的URL对应的状态信息。

title:可以不传

url:要跳转到的URL地址,不能跨域。

history.replaceState(state, title, url)

用新的state和URL替换当前。

不会造成页面刷新。

state:与要跳转到的URL对应的状态信息。

title:可以不传

url:要跳转到的URL地址,不能跨域。


最大区别则在于:

pushState是添加历史记录的,而replaceState是不添加的。


接下来开始讲解两者之间的语法分析:


1、实例

假设http://mozilla.org/foo.html将执行如下JavaScript代码:

varstateObj={foo:"bar"};history.pushState(stateObj,"page2","bar.html");

这将让浏览器的地址栏显示http://mozilla.org/bar.html,但不会加载bar.html页面也不会检查bar.html是否存在。

假设现在用户导航到了http://google.com,然后点击了后退按钮,此时,地址栏将会显示http://mozilla.org/bar.html,并且页面会触发popstate事件,该事件中的状态对象(state object)包含stateObj的一个拷贝。该页面看起来像foo.html,尽管页面内容可能在popstate事件中被修改。

如果我们再次点击后退按钮,URL将变回http://mozilla.org/foo.html,文档将触发另一个popstate事件,这次的状态对象为null。回退同样不会改变文档内容。


2、pushState()方法:添加和修改历史记录条目

①语法:

history.pushState(state,title,url);

pushState()有三个参数:一个状态对象、一个标题(现在会被忽略),一个可选的URL地址。下面来单独考察这三个参数的细节:

状态对象(state object)— 一个JavaScript对象,与用pushState()方法创建的新历史记录条目关联。无论何时用户导航到新创建的状态,popstate事件都会被触发,并且事件对象的state属性都包含历史记录条目的状态对象的拷贝。

任何可序列化的对象都可以被当做状态对象。因为FireFox浏览器会把状态对象保存到用户的硬盘,这样它们就能在用户重启浏览器之后被还原,我们强行限制状态对象的大小为640k。如果你向pushState()方法传递了一个超过该限额的状态对象,该方法会抛出异常。如果你需要存储很大的数据,建议使用sessionStorage或localStorage。

标题(title)— FireFox浏览器目前会忽略该参数,虽然以后可能会用上。考虑到未来可能会对该方法进行修改,传一个空字符串会比较安全。或者,你也可以传入一个简短的标题,标明将要进入的状态。

地址(URL)— 新的历史记录条目的地址。浏览器不会在调用pushState()方法后加载该地址,但之后,可能会试图加载,例如用户重启浏览器。新的URL不一定是绝对路径;如果是相对路径,它将以当前URL为基准;传入的URL与当前URL应该是同源的,否则,pushState()会抛出异常。该参数是可选的;不指定的话则为文档当前URL。

②样例

创建了一个新的由state,title, 和url设定的浏览器历史纪录.

varstate={'page_id':1,'user_id':5};vartitle='HelloWorld';varurl='hello-world.html';history.pushState(state,title,url);


③优势

某种意义上,调用pushState()有点类似于设置window.location='#foo',它们都会在当前文档内创建和激活新的历史记录条目。但pushState()有自己的优势:

新的URL可以是任意的同源URL,与此相反,使用window.location方法时,只有仅修改 hash 才能保证停留在相同的document中。

根据个人需要来决定是否修改URL。相反,设置window.location='#foo',只有在当前hash值不是foo时才创建一条新历史记录。

你可以在新的历史记录条目中添加抽象数据。如果使用基于hash的方法,你只能把相关数据转码成一个很短的字符串。

注意:pushState()方法永远不会触发hashchange事件,即便新的地址只变更了hash。


3、replaceState()方法:修改浏览器当前历史记录条目

history.replaceState()操作类似于history.pushState(),不同之处在于replaceState()方法会修改当前历史记录条目而并非创建新的条目。

当你为了响应用户的某些操作,而要更新当前历史记录条目的状态对象或URL时,使用replaceState()方法会特别合适。


4、popstate事件

每当激活的历史记录发生变化时,都会触发popstate事件。如果被激活的历史记录条目是由pushState所创建,或是被replaceState方法影响到的,popstate事件的状态属性将包含历史记录的状态对象的一个拷贝。

调用history.pushState()或者history.replaceState()不会触发popstate事件.popstate事件只会在其他浏览器操作时触发, 比如点击后退按钮(或者在JavaScript中调用history.back()方法).

当网页加载时,各浏览器对popstate事件是否触发有不同的表现,Chrome 和 Safari会触发popstate事件, 而Firefox不会.

①语法


window.onpopstate=funcRef;

funcRef是个函数名.

②实例

假如当前网页地址为http://example.com/example.html,则运行下述代码后:

window.onpopstate=function(event){alert("location:"+document.location+",state:"+JSON.stringify(event.state));};//绑定事件处理函数.history.pushState({page:1},"title1","?page=1");//添加并激活一个历史记录条目http://example.com/example.html?page=1,条目索引为1history.pushState({page:2},"title2","?page=2");//添加并激活一个历史记录条目http://example.com/example.html?page=2,条目索引为2history.replaceState({page:3},"title3","?page=3");//修改当前激活的历史记录条目http://ex..?page=2变为http://ex..?page=3,条目索引为3history.back();//弹出"location:http://example.com/example.html?page=1,state:{"page":1}"history.back();//弹出"location:http://example.com/example.html,state:nullhistory.go(2);//弹出"location:http://example.com/example.html?page=3,state:{"page":3}

即便进入了那些非pushState和replaceState方法作用过的(比如http://example.com/example.html)没有state对象关联的那些网页,popstate事件也仍然会被触发.


5、读取当前状态

在页面加载时,可能会包含一个非空的状态对象。这种情况是会发生的,例如,如果页面中使用pushState()或replaceState()方法设置了一个状态对象,然后用户重启了浏览器。当页面重新加载时,页面会触发onload事件,但不会触发popstate事件。但是,如果你读取history.state属性,你会得到一个与popstate 事件触发时得到的一样的状态对象。

你可以直接读取当前历史记录条目的状态,而不需要等待popstate事件:

varcurrentState=history.state;


6、浏览器兼容性