JS之BOM篇-history对象
history对象保存了用户从打开窗口那一刻的上网历史记录。出于安全限制,开发人员无法读取用户的历史记录,但是可以通过history提供的方法,在不知道实际URL的情况下实现后退和前进
属性
history.length表示历史记录的URL数量,初始值是1,如果已经访问了3个网址,history.length值就是3
console.log(history.length); // 1
方法
history对象提供了go()、back()、forward()方法,用于操作浏览历史之间的移动
go()
go()方法可以在历史记录中任意跳转,它接收一个整数值作为参数,表示向前或向后的页面数。负数表示向后跳转(类似于后退按钮),正数表示向前跳转(类似于前进按钮),0相当于刷新当前页面
history.go(-1); // 后退一步
history.go(2); // 前进两步
history.go(0); // 刷新当前页
back()
back()方法用于模仿浏览器的后退按钮,相当于history.go(-1)
history.back();
forward()
forward()方法用于模仿浏览器的前进按钮,相当于history.go(1)
history.forward();
注意: 如果移动的位置超出了访问历史的边界,以上三个方法并不报错,而是静默失败。使用历史记录时,页面通常从浏览器缓存之中加载,而不是重新要求服务器发送新的网页
增改记录
HTML5为history对象提供了history.pushState()
和history.replaceState()
方法,用于添加和修改浏览器历史记录。
pushState()
pushState()方法接收三个参数:状态对象stateObject、标题title、URL地址(可选)。该方法向历史记录中添加一个状态
状态对象:状态对象是一个由pushState()方法创建、与历史记录相关的JavaScript对象。当用户定向到一个新状态时会触发popstate事件,该事件有一个state属性,包含了历史记录的state对象。如果不需要状态对象,可以填null
标题:新页面的标题,但是所有浏览器目前都忽略这个值,因此可以填null
URL地址:新历史记录的地址。新URL必须和当前URL在同一个域,否则会报错。该参数是可选的,如果没有提供会被设置为当前文档的URL
history.pushState(state, title, url);
<button id="btn">添加记录</button>
<script>
var stateObj = {posts: 'b'};
btn.onclick = function() {
history.pushState(stateObj, '文章标题', 'b.html')
}
</script>
假设现在的地址是http://127.0.0.1:3030/a.html
,点击添加记录按钮后,地址会变成http://127.0.0.1:3030/b.html
。添加历史记录不会刷新页面,仅仅是视觉上的URL改变,所以点击浏览器的前进和后退按钮,始终显示的是a.html
的内容
注意: 如果URL参数设置了一个新的锚点值,不会触发hashchange事件
<button id="btn">添加记录</button>
<script>
var stateObj = {posts: 'b'};
btn.onclick = function() {
history.pushState(stateObj, null, '#b')
}
window.onhashchange = function(e) {
console.log('hash change')
}
</script>
当地址从http://127.0.0.1:3030/#a
变成http://127.0.0.1:3030/#b
,控制台不会打印hash change
但是下面这种hash变化,是可以监听到的
<body>
<a href="#a">aaa</a>
<a href="#b">bbb</a>
<div id="a"></div>
<div id="b"></div>
<script>
window.onhashchange = function () {
console.log(111);
}
</script>
</body>
replaceState()
history.replaceState()方法的参数与pushState()一样,不同之处在于replaceState()方法会修改当前历史记录条目而并非创建新的条目
<button id="btn">添加记录1</button>
<button id="btn2">添加记录2</button>
<button id="btn3">替换记录2</button>
<script>
btn.onclick = function() {
history.pushState({posts: 'a'}, null, 'a.html')
}
btn2.onclick = function() {
history.pushState({posts: 'b'}, null, 'b.html')
}
btn3.onclick = function() {
history.replaceState({posts: 'c'}, null, 'c.html')
}
</script>
依次点击上面三个按钮,URL变化依次是http://127.0.0.1:3030
=> http://127.0.0.1:3030/a.html
=> http://127.0.0.1:3030/b.html
=> http://127.0.0.1:3030/c.html
。现在点击后退按钮,会跳转到a.html;点击前进按钮,会跳转到c.html。由于b.html被替换掉了,所以不会再出现
state
history.state属性返回当前页面的state对象
btn.onclick = function() {
history.pushState({posts: 'a'}, null, 'a.html')
console.log(history.state) // {posts: "a"}
}
popstate事件
当history对象发生变化时,会触发popstate事件。需要注意的是,只有当用户点击了浏览器的返回和前进按钮,或者使用history的back()、forward()、go()方法时才会触发该事件。仅仅调用pushState方法或replaceState方法,并不会触发该事件。另外,该事件只针对同一文档的切换才有效,如果历史记录的切换导致加载不同的文档,不会触发该事件
<button id="btn">添加记录</button>
<button id="btn2">back</button>
<button id="btn3">forward</button>
<script>
btn.onclick = function() {
history.pushState({posts: 'a'}, null, 'a.html')
}
btn2.onclick = function() {
history.go(-1)
}
btn3.onclick = function() {
history.go(1)
}
window.onpopstate = function(e) {
console.log(e.type, e.state)
}
</script>
添加记录后,点击back返回popstate null
,点击forward返回popstate {posts: "a"}
往返缓存
浏览器有一个特性叫“往返缓存”(back-forward cache或bfcache),可以在用户使用浏览器的“后退”和“前进”按钮时加快页面的转换速度。这个缓存中不仅保存着页面数据,还保存了DOM和javascript的状态;实际上是将整个页面都保存在了内存里。如果页面位于bfcache中,那么再次打开该页面时就不会触发load事件
注意: IE10-浏览器不支持
pageshow
pageshow事件在页面加载时触发,包括第一次加载和从缓存中加载两种情况。如果要指定网页每次加载时都运行的代码,可以放在这个事件的监听函数里
第一次加载时,它的触发顺序排在load事件后面。从缓存加载时,load事件不会触发,pageshow事件会触发
pageshow事件有一个persisted属性,返回一个布尔值。页面没有从缓存加载时,这个属性是false;当页面从缓存加载时,这个属性是true
注意: 必须将其事件处理程序添加到window对象
window.addEventListener('load', function(e) {
console.log('loaded')
})
window.addEventListener('pageshow', function(e) {
console.log(e.persisted)
})
// 'loaded'
// false
pagehide
pagehide事件会在浏览器卸载页面的时候触发,它会在unload事件之前触发
注意: 必须将其事件处理程序添加到window对象
注意: 指定了unload事件处理程序的页面不会从缓存中加载,即使事件处理程序是空的,原因在于unload常用于撤销load中的初始化操作,跳过onload后再次显示页面很可能就会导致页面不正常
pagehide事件的event对象也包含persisted属性,如果页面是从bfcache中加载的,或者页面在卸载之后会被保存在bfcache中,那么persisted的值会被设置为true。因此,当第一次触发pageshow时,persisted的值一定是false,而在第一次触发pagehide时,persisted就会变成true(除非页面不会被保存在bfcache中)
window.addEventListener('pagehide', function(e) {
console.log(e.persisted)
})