1、背景:同事去学校做毕设请假,今天帮他修改h5bug
2、遇到的问题:移动端App打开某个网页会自动弹出一个对话框,这个对话框出现的不合时宜,因为需要是在页面做一些操作后点击原生顶部的返回按钮再弹出对话框
3、具体问题就是popstate造成的
4、原来的代码:
window.addEventListener('popstate', function() {
var btnArray = ['我要退出', '继续计数'];
mui.confirm('正在计数哦,确定要退出吗?', '提示', btnArray, function(e) {
if(e.index == 1) {
pushHistory();
} else {
setBack();
}
})
},false);
5、修改后的代码:
window.addEventListener('load', function() {
setTimeout(function() {
window.addEventListener('popstate', function() {
var btnArray = ['我要退出', '继续计数'];
mui.confirm('正在计数哦,确定要退出吗?', '提示', btnArray, function(e) {
if(e.index == 1) {
pushHistory();
} else {
setBack();
}
})
});
}, 0);
});
6、暂且先解决问题,日后有时间继续深入研究
研究一阵
7、说说过去
以前浏览器操作浏览器历史记录主要依据history对象。在它的proto继承有back、forward、go等函数,那么什么是popState?简而言之就是HTML5新增的用来控制浏览器历史记录的api。
8、怎么用?
HTML5的新API扩展了window.history,使历史记录点更加开放了。可以存储当前历史记录点pushState、替换当前历史记录点replaceState、监听历史记录点popstate。
history.pushState(data,title,url);
//其中第一个参数data是给state的值;第二个参数title为页面的标题,但当前所有浏览器都忽略这个参数,传个空字符串就好;第三个参数url是你想要去的链接;
replaceState用法类似,例如:history.replaceState(“首页”,”“,location.href+ “#web”);
两者区别:pushState会改变history.length,而replaceState不改变history.length
9、有坑吗?
popstate事件在webkit中的很诡异。popstate是HTML5的History系列中的事件,但是这玩意儿在webkit中的行为相当让人蛋疼。这回连IE10都站在了Firefox这边,至少这边的实用性强的多。虽然官方的文档中对popstate的描述也没有细节上的描述,不过以我的逻辑来判断,这货是就webkit的BUG。
Html5这套ApI和传统的history不同,或者说这套API是“session history entries”。
注意注意:Html5种的HistoryAPI是不会使页面跳转的,只是操作地址栏和相应的state属性而已,而且它是手动操作的。浏览器默认的History还是传统的那一套,虽然它们在浏览器上都使用同一个“历史记录堆栈”。
对这个差异的认知就是webkit中诡异行为的原因。webkit并没有把HTML5的History和传统的区分开,而根据官方文档对popstate的描述,只要访问历史记录就会触发popstate。而传统的History中访问页面和生产历史记录是同时的。所以在webkit中,无论是刷新还是访问一个新网页都会触发popstate。而其它浏览器中这个popstate仅作用于HTML5的History,并不响应传统的History,更不用说刷新和访问新网页的情况了。
原因找到了,那么解决方案呢?
1、对popstate延迟绑定的方法,因为popstate会在页面加载完成之后不久触发,所以在setTimeout一段时间后再绑定事件,popstate的第一次就不会轻易被webkit夺走了
2、判断浏览器再做调整,直接针对webkit在页面加载完成后第一次触发的popstate屏蔽了