新版Chromium内核谷歌Edge浏览器实现网页关闭前询问是否确认刷新时不提示

最近遇到一个需求,客户的web系统为了避免领导误点击关闭整个网页,要求点击右上角的关闭按钮(或者标签页的关闭按钮)时,先询问是否真的要关闭,如果点是,则关闭网页,否则无动作;同时要求刷新网页或者点击页面的超链接跳转时无动作(即区分是刷新还是关闭页面,只有页面关闭时触发事件)。PS:客户系统未使用任何前端框架(Vue等),需要原生JS解决问题;需要适配的环境:2023年当前版本的Microsoft Edge浏览器、Chrome谷歌浏览器(80以上)和Firefox火狐浏览器,IE及早期版本谷歌浏览器的无需适配。

十几年前就用过Javascript的onbeforeunload事件,当时是IE一统天下的时代,这个需求非常好实现,但webkit早已统治了浏览器市场多年,连微软的Edge也换成了Google的chromium内核,十几年的发展很多情况发生了变化,过去的方案已经不能使用(百度来的哪些解决办法几乎都不能用了)。

经过几个小时谷歌和百度外加GPT的搜索,中文圈内约95%的解决方案已经没有参考价值,主要原因有二。首先是谷歌从2016年4月发布的版本为“51”的chrome浏览器时便取消了了onbeforeunload事件的自定义提示字符串功能,随后的版本也陆续禁止了事件中使用逻辑语句和alert、confirm等代码的执行。官方当时的表述如下:

从 Chrome 51 开始,onbeforeunload触发时系统将不再向用户显示自定义字符串。Chrome 仍会显示一个对话框,以防止用户丢失数据,但其内容将由浏览器而不是网页设置。

也就是说,通过onbeforeunload事件中event.preventDefault阻止默认事件,再进行逻辑判断的方案已经行不通(亲测不可行)。另外目前官方推荐的Fetch的keepalive属性和sendBeacon()方法我也研究了,它俩主要是能在onbeforeunload事件触发时向后台异步发送消息,尽管可以区分刷新和关闭,但反而实现不了我的简单要求,因此必须找一个相对能接受的方案,即便方案不那么可靠,也总比完全实现不了强。

于是我的要求又降低了:

1,妥协到页面关闭时接受Chrome默认弹出的对话框,接受对话框的文字内容保持浏览器默认,不再寻求自定义。
2,页面刷新或跳转时不弹出对话框
3,功能在大多数情况下能实现即可(即便偶尔关闭时触发不了对话框事件也不要紧,毕竟以应付领导为主,但至少要大概率复现)

再次在搜索引擎中扒拉,几个小时以后终于有所发现:

尽管现在onbeforeunload()事件中不能直接写逻辑判断了,但是可以调用函数;同时onbeforeunload事件中如果return一个“null”值或者“undefined”值(仅有这两种情况)时,浏览器默认的对话框将不会弹出(即不会执行默认事件),如果return其他值时,默认的对话框就会弹出。于是我构思了一个简单的方法,写一个函数来判断事件触发时鼠标的位置,如果再鼠标的X和Y值在右上角(大体位置即可),那么函数就返回一个非空值(如空字符串),反之则返回null。然后onbeforeunload()事件中直接return这个函数,则可以不太精准的实现所需的功能,即只有页面关闭时给出提示,刷新和跳转时无动作。之所以说不太精准,就是鼠标的位置并不好确认,如果鼠标移动过快,onmousemove()方法有可能识别不到最后鼠标停留的坐标导致判断失误,所以鼠标位置限定的范围就需要给大一点(如:X值可以时浏览器宽度-200,Y值可以是100),这种模糊方式就导致了事件触发的可靠性不那么高,不过作为应付的方案,确实可以实现这样的功能。思路搞明白了,方法就很简单了,详细代码如下:


<script
>
/*主页面关闭时提醒,刷新时不提醒*/
var mousewidth = 0;
var mouseheight = 0;


//实时取得当前鼠标的坐标
document.onmousemove = function(e){
mousewidth = e.clientX;
mouseheight = e.clientY;
}


//页面关闭事件
window.onbeforeunload = function(e) {
return closecheck();//根据不同情况返回null或者非null
};


//根据鼠标坐标返回不同值的函数
function closecheck(){
//这里之所以使用mousewidth>150,考虑到了如果点击了标签页的叉号,也认为是关闭;
//所以这就是个模糊判断,并不精确
if(mousewidth>150 && mouseheight<100){
//关闭
return '';
}else{
//刷新
return null;
}
}
</script>

以上代码在Chrome 100+和Microsoft Edge中测试通过,鼠标移动慢一点的话大概率还是会成功的。
这个方案尽管不那么靠谱,但是作为应付的解决办法,还是可行的,如果您有改进方案,请给我留言。

免责声明:文章内容不代表本站立场,本站不对其内容的真实性、完整性、准确性给予任何担保、暗示和承诺,仅供读者参考,文章版权归原作者所有。如本文内容影响到您的合法权益(内容、图片等),请及时联系本站,我们会及时删除处理。

为您推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注