pushState模拟页面后退触发自定义弹窗

需求:在h5游戏页面,当用户首次点击后退按钮、退出当前页面之前,弹出自定义的弹窗提示。

beforeunload/unload

beforeunload/unload 的触发
当离开当前页面时,会触发 beforeunload;比如以下操作:

  1. 关闭浏览器窗口
  2. 点击返回、前进、主页,刷新页面
  3. window.open(),location.href=’’,submit提交表单,等

beforeunload 与 unload 触发时间的区别:
beforeunload 是在没新页面跳转之前触发,此时新页面的新资源请求尚未发出;
unload 是在旧资源已经卸载,新页面的新资源请求已经发出,但新页面还没替换旧页面的时候触发的;
总结: beforeunload 在 unload 之前触发。

beforeunload 与 unload 的使用示例:

1
2
3
window.addEventListener('beforeunload', function (e) {
return '离开页面后、当前的游戏数据将不被保存;确定要离开?';
});

此时,当用户点击触发页面后退时,浏览器会弹出默认弹窗提示。
这个默认的弹窗,是浏览器内置的事件;该事件并未对开发者提供可以自定义弹窗的交互接口,开发者不能自定义。
因此,beforeunload/unload 不能实现后退时弹窗自定义弹窗的需求。

pushState/popstate

history.pushState() 方法向浏览器历史添加了一个状态。
history.pushState(state object, title, URL),带有三个参数:
一个状态对象,一个标题(现在被忽略了),以及一个可选的URL地址。详见 History.pushState()

popstate 事件的触发:
点击后退、前进按钮(或者在JavaScript中调用 history.back()、history.forward()、history.go()方法);
调用 history.pushState() 或者 history.replaceState() 不会触发popstate事件

注意点:

  1. History.pushState()可以改变当前 url,但不会刷新页面;
  2. 点击后退离开当前页面,当前的 url 要发生变化(触发hash值的变化);
  3. hash值的变化不会刷新当前页面,会触发popstate事件

页面后退自定义弹窗

基本思路:

  1. 进入页面,当前 url 为: a.com/game.html
  2. 进入页面后,立即 pushState 一个新链接(追加了hash值)到 history 中,改变了链接但页面没刷新,此时 url 为 a.com/game.html#leaveStatus;同时将变量 leaveStatus = 1
  3. 用户点击了后退,此时 url 后退到 a.com/game.html,但页面未刷新;同时触发了 popstate 事件;
  4. 触发了 popstate 事件,若此时 leaveStatus = 1,则显示自定义弹窗

具体实现代码(新增了cookie设置,一天内不再弹窗):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var Tool = {
getCookie: function(cname){
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++)
{
var c = ca[i].trim();
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
}
return "";
},
};
var leaveStatus = 0;
window.addEventListener('load', function() {
var tit = document.title,
path;
//首次进入页面时才加入#leaveStatus;当只是刷新页面时,不再重复加入#leaveStatus
if(location.hash != '#leaveStatus'){
path = location.href.replace(/#.*$/, '') + '#leaveStatus';
// 将追加了hash的链接推入history中
history.pushState({
title: tit,
path: path
},
tit, path);
}
leaveStatus = 1;
});
window.addEventListener('popstate', function(ev) {
var isPop = Tool.getCookie('isPop');
if(isPop == 'no'){
window.history.go(-1);
}else{
if (leaveStatus == 1) {
leaveStatus = 0;
//myPop(); //执行自定义弹窗效果
}
}
});

the end 。