hashchange
与popstate
事件都是浏览器历史记录API,二者都是HTML5中的API,相对而言popstate
比hashchange
更为强大。注意这两种历史记录管理都受同源策略的限制,这里厘清下二者的区别以及相关应用:javascript
hashchange
事件是在浏览器URL中hash发生变化后触发的事件(事件触发后会在浏览器历史记录中添加一条记录),URL中#
后的内容就是hash,它的变化所触发的hashchange
事件与ajax搭配最多。 按个人理解, 由于hash变化并不会向服务器发生请求,因此若是没有hashchange
事件,当咱们点击浏览器前进和后退按钮时,服务器没法做出反应(由于服务器没法收到请求), 有了这个事件,就可使用js触发ajax的新请求让服务器做出响应。hashchange
事件自己只是监测hash的变化,我认为目前其主要意义就是与ajax搭配使用从而使得在ajax下历史记录前进后退按钮依然有效。可使用如下简单的代码体会下:html
<!doctype html> <html> <head> <meta charset="UTF-8"> <title>hashchange</title> </head> <body onhashchange="alert('Got a hashchange.');"> <a href='#foo'>Click me foo</a> <a href='#bar'>Click me bar</a> </body> </html>
hashchange的文档mark? hashchangejava
popstate
事件通常与pushState()
和replaceState()
这两个方法搭配使用, 当用户点击浏览器的前进后退按钮时, 支持该事件的浏览器就会触发popState
事件,顾名思义,该事件所pop的正是由pushState()
方法所保存的状态栈,这里简单替下pushState()
方法的语法,引用自MDN文档(注意该文档中特地指出了firefox对该方法实现的差别, 好比对title的忽略)?操纵浏览器的历史记录:ajax
pushState(object,title,url)浏览器
状态对象(state object) — 一个JavaScript对象,与用pushState()方法建立的新历史记录条目关联。不管什么时候用户导航到新建立的状态,popstate事件都会被触发,而且事件对象的state属性都包含历史记录条目的状态对象的拷贝。
任何可序列化的对象均可以被当作状态对象。由于FireFox浏览器会把状态对象保存到用户的硬盘,这样它们就能在用户重启浏览器以后被还原,咱们强行限制状态对象的大小为640k。若是你向pushState()方法传递了一个超过该限额的状态对象,该方法会抛出异常。若是你须要存储很大的数据,建议使用sessionStorage或localStorage。安全
标题(title) — FireFox浏览器目前会忽略该参数,虽然之后可能会用上。考虑到将来可能会对该方法进行修改,传一个空字符串会比较安全。或者,你也能够传入一个简短的标题,标明将要进入的状态。服务器
地址(URL) — 新的历史记录条目的地址。浏览器不会在调用pushState()方法后加载该地址,但以后,可能会试图加载,例如用户重启浏览器。新的URL不必定是绝对路径;若是是相对路径,它将以当前URL为基准;传入的URL与当前URL应该是同源的,不然,pushState()会抛出异常。该参数是可选的;不指定的话则为文档当前URL。session
每次触发popstate
事件后,事件对象中state属性保存了以前经过pushState()
方法压入的状态对象。在《javascript权威指南》中例22-3很生动地展现了该用法,这里将这个例子放在codepen中(点击连接打开,每次猜想数字后使用浏览器前进后退按钮观察状态恢复),一些注释我从新写了一下便于理解,可直接在codepen中查看源码:
DEMO ?基于popstate的猜数字游戏url
这里顺带提下replaceState()
,这个方法与pushState()
语法相似,但它是用第一个参数(状态对象)主动替代当前状态,它并不会在浏览器历史记录中增长历史记录,这点相似于window.location.replace(url)
firefox
hashchange
只有在hash值改变时才能触发,而popstate
在支持它的浏览器中只要按下“前进”“后退”按钮就会在Window对象上触发
popstate
事件能够是任意同源的url下触发,也就是说它能够在example.com/page1 与example.com/page2中均可以触发,而hashchange
只有在example.com/page1#hash中才能够(这点暂时是我的理解,并未实验)
使用事件对象能够抽象数据,而没必要将数据变成字符串加在hash中