
1.4 浏览器相关事件介绍
1.4.1 popstate事件
在history.pushState或history.replaceState产生的历史栈记录中,当移动栈指针或单击浏览器的“前进”或“后退”按钮时,将触发popstate事件,可通过window.addEventListener监听该事件。

监听函数的参数为对应popstate事件的事件对象。对于事件对象event,event.state是重点需要关注的,其为移动后对应栈中记录的state对象,如图1-6所示。

图1-6 各栈记录保存了state对象
当调用history.go(-1)时,事件回调中得到的event.state为{a:1};当调用history.go(1)时,事件回调中得到的event.state为{a:3}。
使用history.pushState或history.replaceState不会触发popstate事件。单击浏览器的“后退”或“前进”按钮,或者调用history的go、back、forward等方法,或者更改部分浏览器的hash,都会触发此事件。在导航跳转完成后,除了可以从popstate事件对象中获取当前的state对象,还可以直接从history中获取当前的state对象,即读取history.state变量的值即可。
需要注意的是,由于部分浏览器对popstate事件的实现不一致,当网页加载完成后,部分浏览器会触发popstate事件,而部分浏览器不会触发popstate事件。当编码时,对于这种情况,可使用history.state获取状态对象state,而不是从popstate事件对象中获取state对象。
注意,在事件中更改event.state,history.state不会被改变,如:

但是直接更改history.state,将会更改history.state的值:

在历史栈指针变化后,history.state将会重新被赋值,即便已经修改过history.state:

由此可知,history.state同步的是栈记录中的值,每次导航都会获得新的state对象。栈记录中的state对象是深拷贝存储在浏览器中的,无论在浏览器中进行导航,还是刷新当前页面,抑或是关闭浏览器页签再恢复,历史栈内的内容都存在且不会被销毁。
当前后两次设置相同的location.hash值时,不会触发两次popstate事件。

若通过location.href设置hash值,如location.href='#/123',则无论前后设置的值是否相同,都会触发popstate事件。当前后两次设置的值相同时,只添加一个历史栈。
