hashchange
与popstate
事件都是浏览器历史记录API,两者都是HTML5中的API,相对而言popstate
比hashchange
更为强大。注意这两种历史记录管理都受同源策略的限制,这里厘清下两者的区别以及相关应用:
hashchange
hashchange
事件是在浏览器URL中hash发生变化后触发的事件(事件触发后会在浏览器历史记录中添加一条记录),URL中#
后的内容就是hash,它的变化所触发的hashchange
事件与ajax搭配最多。 按我的理解, 因为hash变化并不会向服务器发生请求,所以如果没有hashchange
事件,当我们点击浏览器前进和后退按钮时,服务器无法作出反应(因为服务器无法收到请求), 有了这个事件,就可以使用js触发ajax的新请求让服务器作出响应。hashchange
事件本身只是监测hash的变化,我认为目前其主要意义就是与ajax搭配使用从而使得在ajax下历史记录前进后退按钮依然有效。可以使用以下简单的代码体会下:
<!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? hashchange
popstate
popstate
事件一般与pushState()
和replaceState()
这两个方法搭配使用, 当用户点击浏览器的前进后退按钮时, 支持该事件的浏览器就会触发popState
事件,顾名思义,该事件所pop的正是由pushState()
方法所保存的状态栈,这里简单替下pushState()
方法的语法,引用自MDN文档(注意该文档中特意指出了firefox对该方法实现的差异, 比如对title的忽略)?操纵浏览器的历史记录:
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。
每次触发popstate
事件后,事件对象中state属性保存了之前通过pushState()
方法压入的状态对象。在《javascript权威指南》中例22-3很生动地展示了该用法,这里将这个例子放在codepen中(点击链接打开,每次猜测数字后使用浏览器前进后退按钮观察状态恢复),一些注释我重新写了一下便于理解,可直接在codepen中查看源码:
DEMO ?基于popstate的猜数字游戏
这里顺带提下replaceState()
,这个方法与pushState()
语法类似,但它是用第一个参数(状态对象)主动替代当前状态,它并不会在浏览器历史记录中增加历史记录,这点类似于window.location.replace(url)
hashchange与popstate的区别归纳
hashchange
只有在hash值改变时才能触发,而popstate
在支持它的浏览器中只要按下“前进”“后退”按钮就会在Window对象上触发popstate
事件可以是任意同源的url下触发,也就是说它可以在example.com/page1 与example.com/page2中都可以触发,而hashchange
只有在example.com/page1#hash中才可以(这点暂时是个人理解,并未实验)使用事件对象可以抽象数据,而不必将数据变成字符串加在hash中