如何覆盖OnBeforeUnload对话框并将其替换为我自己的对话框?


346

我需要在用户离开页面之前警告用户有关未保存的更改的信息(这是一个非常常见的问题)。

window.onbeforeunload=handler

这可以工作,但是会引发一个默认对话框,其中包含包装我自己的文本的刺激性标准消息。我需要完全替换标准消息,以便文本清晰,或者(甚至更好)使用jQuery将整个对话框替换为模式对话框。

到目前为止,我失败了,但是我还没有找到其他似乎有答案的人。可能吗

我页面中的Javascript:

<script type="text/javascript">   
   window.onbeforeunload=closeIt;
</script>

closeIt()函数:

function closeIt()
{
  if (changes == "true" || files == "true")
  {
      return "Here you can append a custom message to the default dialog.";
  }
}

我使用jQuery和jqModal尝试了这种事情(使用自定义确认对话框):

$(window).beforeunload(function() {
        confirm('new message: ' + this.href + ' !', this.href);
        return false;
    });

这也行不通-我似乎无法绑定到beforeunload事件。


1
您能举例说明当前代码及其产生的结果吗?
Owen

欧文是正确的。而且,其背后的原因是安全性。阻止页面卸载在Web表单等中很有用,但是恶意站点很容易利用它来欺骗用户,使其停留在页面上。这就是为什么Web浏览器实现标准消息并具有插入自定义文本的机制。
pluckyglen



Answers:


299

您无法修改的默认对话框onbeforeunload,因此最好的选择是使用它。

window.onbeforeunload = function() {
    return 'You have unsaved changes!';
}

这是 Microsoft对此的参考

当将字符串分配给window.event的returnValue属性时,将出现一个对话框,为用户提供保留在当前页面上并保留分配给它的字符串的选项。对话框中显示的默认语句“您确定要离开此页面吗?...按OK继续,或按Cancel保留在当前页面上。”无法删除或更改。

问题似乎是:

  1. onbeforeunload被调用时,它会采取的处理程序的返回值window.event.returnValue
  2. 然后,它将返回值解析为字符串(除非它为null)。
  3. 由于false被解析为字符串,因此对话框将触发,然后传递适当的true/ false

结果是,似乎没有一种分配false方法onbeforeunload来阻止它与默认对话。

jQuery的其他说明:

  • 在jQuery中设置事件可能会出现问题,因为这onbeforeunload也会导致其他事件发生。如果您只希望发生卸载事件,那么我会坚持使用普通的JavaScript。
  • jQuery没有捷径,onbeforeunload因此您必须使用通用bind语法。

    $(window).bind('beforeunload', function() {} );

编辑09/04/2018:自chrome-51起,onbeforeunload对话框中的自定义消息已弃用(cf:发行说明


20
我发现最后给出的JQuery示例在firefox中不起作用。而是使用简单的方法:window.onbeforeunload = function(){...}
jb。

21
请注意,Firefox最近已更改,因此甚至无法自定义对话框中的文本:bugzilla.mozilla.org/show_bug.cgi?id=588292
David Hammond

15
但是facebook如何提供一个自定义对话框呢?例如,转到消息页面,回复朋友的消息,然后在单击发送之前,尝试单击另一个链接。您会看到一个自定义对话框弹出窗口
-Varun

20
@Varun-旧消息,但Facebook可能会将处理程序置于其所有锚点的click事件上,但是如果您在浏览器中重写URL或关闭窗口,它将恢复为他们无法控制的标准方法。
Tabloo Quijico

1
@Varun我也很惊讶,这个不可能实现的答案被标记为答案,并有150票赞成票...刚意识到,FB的自定义消息仅可通过其站点内的链接获得。如果你不只是浏览了......
塞巴斯蒂安更丰富的

28

使用jQuery并在IE8,Chrome和Firefox中测试过的对我有用的是:

$(window).bind("beforeunload",function(event) {
    if(hasChanged) return "You have unsaved changes";
});

如果不需要提示,请不要返回任何内容,因为IE与其他浏览器行为之间存在差异,这一点很重要。


有趣, event.returnValue是IE中唯一的“批准”方法。IE 继续说: “此属性的值优先于函数返回的值,例如通过Microsoft JScript return语句返回的值。” ..这将是很好看之间的相关性保证return(自事件)和event.returnValue..

21

尽管在某些情况下您无法对此框做任何事情,但是您可以拦截某人单击链接。对于我来说,这在大多数情况下都是值得的,作为后备,我已经离开了卸载事件。

我使用了Boxy而不是标准的jQuery对话框,可在此处使用:http : //onehackoranother.com/projects/jquery/boxy/

$(':input').change(function() {
    if(!is_dirty){
        // When the user changes a field on this page, set our is_dirty flag.
        is_dirty = true;
    }
});

$('a').mousedown(function(e) {
    if(is_dirty) {
        // if the user navigates away from this page via an anchor link, 
        //    popup a new boxy confirmation.
        answer = Boxy.confirm("You have made some changes which you might want to save.");
    }
});

window.onbeforeunload = function() {
if((is_dirty)&&(!answer)){
            // call this if the box wasn't shown.
    return 'You have made some changes which you might want to save.';
    }
};

您可以附加到另一个事件,并根据单击的锚点类型进行更多过滤,但这对我和我想做的事情都有效,并作为其他人使用或改进的示例。我想与那些想要此解决方案的人分享一下。

我已经剪掉了代码,所以这可能无法正常工作。


返回“您已进行了一些可能要保存的更改。” 没有为我工作。我必须将消息存储在变量“ warning_message”中,并且确实返回warning_message。然后只有它对我有用!
Suganya

您是否在IE,Chrome,Firefox中进行过测试?
Kiquenet

9

1)使用onbeforeunload,而不是onunload。

2)重要的是要避免执行return语句。我并不是说要避免从处理程序中返回。您可以返回正确的所有结果,但是可以通过确保到达函数的末尾并且不要执行return语句来做到这一点。在这些情况下,不会发生内置的标准对话框。

3)如果使用onbeforeunload,可以在unbeforeunload处理程序中运行ajax调用以整理服务器,但是它必须是同步的,并且您必须等待并处理onbeforeunload处理程序中的回复(仍然要尊重条件(2))。我这样做,并且效果很好。如果您执行同步ajax调用,则所有内容都会保留,直到响应返回为止。如果您执行异步操作,以为您不在乎服务器的答复,则页面卸载将继续,并且此过程将中止ajax调用-如果正在运行,则包括远程脚本。


仅供参考,任何人都在读这篇文章^ Chrome正在弃用unbeforeunload中的同步AJAX调用
morganwebdev

4

尝试放置一个return;而不是一条消息。这对我来说大多数浏览器都有效。(这只会阻止对话框的出现)

window.onbeforeunload = function(evt) {            
        //Your Extra Code
        return;
}

3
返回null将阻止对话框打开
Brett Weber

1
返回null不会阻止对话框打开。我在Chrome中尝试过了,事实并非如此。

2
我也可以在IE中确认Ray的评论。返回null将打开一个对话框,显示文本为“ null”。但是,return void(0);不会打开对话框。
MCattle

1
通过不将任何return语句放入beforeunload函数中,该对话框将不会打开。
OuuGiii


3

您可以检测到用户按下了哪个按钮(确定或取消),因为onunload函数仅在用户选择离开页面时才调用。Althoug在此功能中的可能性是有限的,因为DOM正在崩溃。您可以运行javascript,但是ajax POST不会执行任何操作,因此您不能使用此方法进行自动注销。但是有一个解决方案。window.open('logout.php')在onunload函数中执行,因此用户将以新的窗口打开注销。

function onunload = (){
    window.open('logout.php');
}

当用户离开页面或关闭活动窗口并由“ logout.php”注销时,将调用此代码。注销php包含以下代码后,新窗口将立即关闭:

window.close();

您可以在beforeunload和unload函数中使用同步发布。特别是如果您需要从服务器返回数据。在页面卸载时,这些块中的任何异步代码都可能无法完成。
jemiloii '16

3

我遇到了同样的问题,我可以使用自己的消息来获得自己的对话框,但是我遇到的问题是:1)它在所有导航中都给出了消息,我只希望单击即可。2)带有我自己的确认消息,如果用户选择“取消”,它仍显示浏览器的默认对话框。

以下是找到的解决方案代码,这些代码是我在“主页”上编写的。

function closeMe(evt) {
    if (typeof evt == 'undefined') {
        evt = window.event; }
    if (evt && evt.clientX >= (window.event.screenX - 150) &&
        evt.clientY >= -150 && evt.clientY <= 0) {
        return "Do you want to log out of your current session?";
    }
}
window.onbeforeunload = closeMe;


1

如何使用“ bind”命令“ one”的专用版本。一旦事件处理程序第一次执行,它将作为事件处理程序自动删除。

$(window).one("beforeunload", BeforeUnload);

非常确定这是.on(“ beforeunload”
Sergiu Mindras '18

2
@SergiuMindras不,它是.one()-附加了事件侦听器以侦听事件仅发生一次:“将处理程序附加到元素的事件。该处理程序对于每种事件类型,每个元素最多执行一次。” api.jquery.com/one-
肖恩·

0

Angular 9方法:

constructor() {
    window.addEventListener('beforeunload', (event: BeforeUnloadEvent) => {
     if (this.generatedBarcodeIndex) {
      event.preventDefault(); // for Firefox
      event.returnValue = ''; // for Chrome
      return '';
     }
     return false;
    });
   }

浏览器支持和自定义消息的删除:

  • Chrome在51分钟内删除了对自定义消息的支持
  • Opera在38分钟内删除了对自定义消息的支持
  • Firefox在44.0分钟内删除了对自定义消息的支持
  • Safari在9.1分钟内删除了对自定义消息的支持
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.