一、需求背景
- 1、当前页有一个弹窗,当用户浏览器后退的时候不希望直接退出,而是将当前弹窗进行关闭,留在当前页
- 2、用户进入当前页点击浏览器后退的时候不希望用户直接退出,使用浏览器后退跳转到其它页面,增加流量
二、功能实现
使用浏览器API window.history 进行后退控制,需要浏览器支持history
(大部分移动浏览器都支持了) 代码示例:
// 添加浏览器历史纪录
history.pushState('test', '', '')
// 监听浏览器后退事件
window.onpopstate = function (e) {
// 这里进行业务逻辑的处理
location.href = 'c.html'
}
这样在页面加载的时候添加入新的浏览器纪录就可以在后退的时候触发 popState 事件,然后处理你的业务逻辑
三、遇到的BUG
- 1、
history.pushState
在当前页面刷新一次页面就会添加一次,当多次刷新的时候会将history
的长度加长,需要使用一个存储变量进行判断是否需要添加历史纪录,显然H5新接口sessionStorage
很适合当前使用,这样在跳转到后退页面之后在使用浏览器后退会返回到当前页,由于使用了判断是当前页不再进行历史压栈,就不会在重新触发popState
事件了,避免了无限次浏览器后退无限循环。
let active_view = sessionStorage.getItem('active_view')
if (!active_view) {
sessionStorage.setItem('active_view', 'has')
}
- 2、Ios微信浏览器
popstate
的bug,在当前A.html页跳转到b.html页,然后再b.html页通过浏览器返回按钮回到a.html页面的时候会直接触发popState
事件,直接跳转到c.html页面了,真实需求是再b.html返回的时候回到a.html页面,然后在a.html页面的后退的时候才进行跳转c.html页面。所以我将Ios和Android区分开来,分别进行不同的业务处理。
// 判断ios 的时候在第二次返回才进行页面跳转,不是的在重新将history增加
let jumps: any = sessionStorage.getItem('jump_number') || 0;
let count = parseInt(jumps) + 1;
let u = navigator.userAgent;
let isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
sessionStorage.setItem('jump_number', count);
if (isIOS) {
if (count >= 2) {
// ios
setJump();
} else {
pushHistory();
}
} else {
// 其它
setJump();
}
- 3、页面跳转问题,在微信浏览器中直接使用
location.href = c.html
有可能页面不会替换,其实显示的还是a.html,需要点击刷新页面才是c.html,所以封装了一个跳转函数,加上一段打印log就可以正常跳转了
// 需要将url打印出来页面跳转才会正常,(发稿之前还未弄清楚是什么原因,以后知道了在附上)
function setJump(url) {
// 跳转
console.log('链接:' + url);
window.location.href = url;
}
- 4、当使用
history.pushState(state, "test", "#")
添加参数的时候,如果当前页面的url中有#号,就是最后一个参数和url中最后的字符相同,会破坏popState
事件,可能导致不触发,因此使用参数加入历史的需要注意投放链接的url,Android 手机部分机型在此情况下点击浏览器后退也会触发两次popState
事件
// push 浏览器历史记录
function pushHistory() {
let state = {
title: "test",
url: "#"
};
window.history.pushState(state, "test", "#")
}
总结
- 1、H5 页面需要在很多平台进行运行,有些是微信、支付宝内置浏览器的问题,也有很多是手机平台的问题,需要兼容许多机型和平台的问题,比较复杂还有更多的平台兼容问题需要去处理。
- 2、不同平台对于
window
的API有一些差异,许多BUG都是该差异引起的,所以在遇到的时候多查查资料就可以了。
开发环境的问题
- 1、大多数前端同学都是使用谷歌浏览器作为开发浏览器的。新版的谷歌浏览器点击后退按钮不会触发
popState
事件,需要在控制台打印history.length
在点击后退按钮才会触发(还不知道这个原因是什么)