History 控制前进后退
日常项目开发中常会遇到全屏弹窗的需求,全屏弹窗会给人一种新打开窗口的感觉,用户会觉得用后退(🔙)按钮或者一些Android手机自带物理后退按钮可以返回到上一页,而实际上两个是同一个页面,后退会返回到当前页的前一页,使用History可以解决这个问题
这里有一篇不错的 history 介绍,下面大部分为引用
History.pushState()
History.pushState()用于在history中添加一条记录
window.history.pushState(state, title, url)
-
state: 一个与添加的记录相关联的状态对象,主要用于
popstate事件。该事件触发时,该对象会传入回调函数。也就是说,浏览器会将这个对象序列化以后保留在本地,重新载入这个页面的时候,可以拿到这个对象。如果不需要这个对象,此处可以填null。 -
title: 新页面的标题。但是,现在所有浏览器都忽视这个参数,所以这里可以填空字符串。
-
url: 新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。
假设当前网页为example.com
history.pushState(null, '', 'foo.html')
// url变为 example.com/foo.html history增加一条记录
history.pushState(null, '', '?id=1')
// url变为 example.com/foo.html?id=1 history增加一条记录
history.pushState(null, '', '#foo')
// url变为 example.com/foo.html?id=1#foo history增加一条记录
history.pushState(null, '', 'foo.html')
// url变为 example.com/foo.html history增加一条记录
History.replaceState()
History.replaceState()用于替换当前history的记录
无论是History.replaceState()还是History.pushState()都只是替换当前地址栏的地址,不会触发刷新页面,也不会检测该页面是否存在,当你访问一个新的地址后点击返回时,之前修改的地址就会出现
popstate 事件
每当同一个文档的浏览历史(即history对象)出现变化时,就会触发popstate事件。
注意,仅仅调用pushState()方法或replaceState()方法 ,并不会触发该事件,只有用户点击浏览器倒退按钮和前进按钮,或者使用 JavaScript 调用History.back()、History.forward()、History.go()方法时才会触发。另外,该事件只针对同一个文档,如果浏览历史的切换,导致加载不同的文档,该事件也不会触发。
使用的时候,可以为popstate事件指定回调函数。
window.onpopstate = function (event) {
console.log('location: ' + document.location);
console.log('state: ' + JSON.stringify(event.state));
};
// 或者
window.addEventListener('popstate', function(event) {
console.log('location: ' + document.location);
console.log('state: ' + JSON.stringify(event.state));
});
回调函数的参数是一个event事件对象,它的state属性指向pushState和replaceState方法为当前 URL 所提供的状态对象(即这两个方法的第一个参数)。上面代码中的event.state,就是通过pushState和replaceState方法,为当前 URL 绑定的state对象。
这个state对象也可以直接通过history对象读取。
var currentState = history.state;
注意,页面第一次加载的时候,浏览器不会触发popstate事件。
demo
接下来我们完成一个demo,通过后退和前进按钮完成对页面模态框的显示隐藏控制
html
<div class="btn" id="btn">显示遮罩</div>
<div class="overlay" id="overlay"></div>
js
function showModal() {
history.pushState({action: 'showModal'}, '', 'history.html')
overlay.style.display = 'block'
}
window.addEventListener('popstate', function(e) {
console.log('popstate', e)
// 注意这里触发是在histroy已经pop完了之后
if (history.state) {
if (history.state.action === 'showModal') {
overlay.style.display = 'block'
} else {
console.log('never console')
}
} else {
overlay.style.display = 'none'
}
})
btn.onclick = showModal