拦截页面退出事件


117

在我的系统中编辑页面时,用户可能决定导航到另一个网站,这样做可能会丢失所有尚未保存的编辑内容。

我想拦截任何尝试转到另一个页面的尝试,并提示用户确保他们希望这样做,因为他们可能会丢失当前的工作。

Gmail的执行方式与此非常相似。例如,撰写一封新电子邮件,开始在邮件正文中键入内容,然后在地址栏中输入新位置(例如twitter.com等)。它将提示您“确定吗?”

想法该如何复制?我的目标是IE8,但也希望与FF和Chrome兼容。


Answers:


154

与Ghommey的答案类似,但这也支持IE和Firefox的旧版本。

window.onbeforeunload = function (e) {
  var message = "Your confirmation message goes here.",
  e = e || window.event;
  // For IE and Firefox
  if (e) {
    e.returnValue = message;
  }

  // For Safari
  return message;
};

1
您能解释第一行(var message = ...)吗?我不知道该逗号和第二个表达式在做什么。
mtmurdock 2012年

7
@mtmurdock这只是声明多个变量的Javascript语法。 var foo, bar;var foo; var bar;
T Nguyen

4
@mtmurdock,第二条语句“ var e = e || window.event;” 表示将e设置为等于参数e(如果为真)或window.event(如果不为真)。如果参数e为null ,则不会是真的。
T Nguyen

3
IE8不支持@Blieque addEventListener。在没有阅读问题之前,不要编辑别人的答案。
伊莱·格雷

2
不工作在Chrome的话(不推荐):developers.google.com/web/updates/2016/04/...
米莎·施瓦布

25

请参阅本文。您正在寻找的功能是onbeforeunload

样例代码:

  <script language="JavaScript">
  window.onbeforeunload = confirmExit;
  function confirmExit()
  {
    return "You have attempted to leave this page.  If you have made any changes to the fields without clicking the Save button, your changes will be lost.  Are you sure you want to exit this page?";
  }
</script>

2
有什么方法可以识别用户选择了“离开此页面”选项,而不是“停留在此页面上”?
Shilpa Soni

@ShilpaSoni,您很快就会收到随后的卸载事件,developer.mozilla.org / en-US / docs / Web / API / Window / unload_event,但我认为没有同步的方法。
scipilot

6

与其烦人的确认弹出窗口,不如延迟一小段时间(毫秒)来成功地将未保存的数据成功发布到服务器,这是我很好的做法,我使用这样的虚拟文本向控制台进行管理:

window.onbeforeunload=function(e){
  // only take action (iterate) if my SCHEDULED_REQUEST object contains data        
  for (var key in SCHEDULED_REQUEST){   
    postRequest(SCHEDULED_REQUEST); // post and empty SCHEDULED_REQUEST object
    for (var i=0;i<1000;i++){
      // do something unnoticable but time consuming like writing a lot to console
      console.log('buying some time to finish saving data'); 
    };
    break;
  };
}; // no return string --> user will leave as normal but data is send to server

编辑: 另请参见Synchronous_AJAX以及如何使用jquery


我喜欢这种替代弹出窗口的方法。感谢您的建议,雷米。
克里斯·巴伦斯

2
那绝对没有意义-1。javascript没有线程化,您正在做的事情是执行postRequest,然后暂停网站的计算而没有任何人不能做任何事情(包括您的postRequest,这是在计算暂停之前已经发送的)。
fmsf 2012年

这就是它起作用的原因:确实在计算暂停之前发送了后请求,但是在页面实际离开之前对页面的一点阻塞确保了浏览器客户端(不是javascript)有足够的时间真正完成正确发送此请求。 。我注意到,当我仅发送请求(无阻塞)并在之后立即离开页面时,请求并不总是发送。
雷米

6
我不会在生产中使用它。console.log不是跨浏览器;每个postRequest都遭受前一个延迟(这也意味着该页面将在您的循环*计划的请求期间挂在那里);请求不是并行开始的;您不能保证真正发送您的请求。如果我被迫面对这个问题,那么如果只有一个请求,我会处理一个同步的ajax请求。对于多个请求,我将使用异步ajax请求和一个循环,该循环从请求的回调中检查结果(成功还是错误)。
framp 2012年

我不知道console.log不是跨浏览器,并且同步Ajax请求确实应该是首选解决方案(对于单个请求)。提到SCHEDULED_REQUEST的对象累积了应该发送到服务器的任何非紧急信息(例如数据缓冲区),从而有效地将多个请求连接到一个请求(当然,这些请求的url是相同的)。如前所述,在卸载之前使用Synchronous Ajax请求可以解决跨浏览器的问题。感谢您的宝贵意见!
雷米(Remi)2012年

0

我的用户尚未完成所有必需的数据。

<cfset unloadCheck=0>//a ColdFusion precheck in my page generation to see if unload check is needed
var erMsg="";
$(document).ready(function(){
<cfif q.myData eq "">
    <cfset unloadCheck=1>
    $("#myInput").change(function(){
        verify(); //function elsewhere that checks all fields and populates erMsg with error messages for any fail(s)
        if(erMsg=="") window.onbeforeunload = null; //all OK so let them pass
        else window.onbeforeunload = confirmExit(); //borrowed from Jantimon above;
    });
});
<cfif unloadCheck><!--- if any are outstanding, set the error message and the unload alert --->
    verify();
    window.onbeforeunload = confirmExit;
    function confirmExit() {return "Data is incomplete for this Case:"+erMsg;}
</cfif>
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.