如何防止浏览器窗口关闭?

60

我尝试了以下代码,以便在关闭浏览器窗口时获取一个警告:

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?";
}

它能够工作,但如果页面包含一个超链接,点击该超链接会引发相同的警报。我需要仅在关闭浏览器窗口时显示警报,而不是在点击超链接时。


2
投票重新开放。链接的重复问题没有回答这个问题,但是这里的答案有。 - Heinzi
就这个问题而言,如果你将这种行为添加到我必须使用的任何应用程序中,我会来踢你粉红色的脚趾。劫持浏览器是一个非常糟糕的解决方案。你不能只是使用 AJAX 或其他什么自动保存他们的状态吗? - Graham
4
我不同意Graham的观点——有时候你只需要一个警告或确认。当然,这可能会被一些网站滥用,试图阻止你离开,但是如果使用得当,它可以受到很多赞赏,例如,如果你忘记发布某些内容。 - devios1
即使您禁用锚点事件,如果要刷新页面,仍然会遇到问题。 - ROMANIA_engineer
4个回答

51

另一种实现方式可以在此网页中找到: http://ujap.de/index.php/view/JavascriptCloseHook

<html>
  <head>
    <script type="text/javascript">
      var hook = true;
      window.onbeforeunload = function() {
        if (hook) {
          return "Did you save your stuff?"
        }
      }
      function unhook() {
        hook=false;
      }
    </script>
  </head>
  <body>
    <!-- this will ask for confirmation: -->
    <a href="http://google.com">external link</a>

    <!-- this will go without asking: -->
    <a href="anotherPage.html" onClick="unhook()">internal link, un-hooked</a>
  </body>
</html>

它的作用是你使用一个变量作为标志。


+1 是因为它是一种更普遍和易于使用的解决方案。假设我有一个脚本部分,使网页重定向,在应用重定向操作之前,我只需设置 hook = false。请查看这个DEMO - SaidbakR
根据您的解决方案,我建议如果您使用 jQuery,则使用类似于 .noConfirm 的类,并执行以下操作:$('.noConfirm').click(unhook) - Meowtwo 117
@netadictos 我建议您更新您的答案,使用更现代的.addEventListener()而不是onclick属性(或.onbeforeunload = ...)。 - Michał Perłakowski
我建议您不要使用addEventListener,因为onclick在所有浏览器中都有效。您仍然可以非侵入式地分配onclick。 - mplungjan
@netadictos - 我可以编写自己的JavaScript代码而不仅仅是确认框吗? - Musaddiq Khan
显示剩余2条评论

33

保持您的代码不变,并使用jQuery处理链接:

$(function () {
  $("a").click(function {
    window.onbeforeunload = null;
  });
});

如果打开的子窗口在另一个域中,这个能行吗? - Muhammad Hassan Nasr
是的,它适用于链接,但请提供一个解决方案,当我们刷新浏览器时,window.onbeforeunload事件会触发,如何停止在刷新页面或按下后退按钮时触发该事件?你有任何想法吗? - Aitazaz Khan
7
这个问题没有jQuery标签。 - Michał Perłakowski
1
@M.UtkuALTINKAYA 你是什么意思?这个问题还没有jQuery标签。 - Michał Perłakowski
2
@M.UtkuALTINKAYA 他的意思是问题中没有jQuery标签,因此你不应该用jQuery解决方案回答。使用原生JavaScript会更好。 - Ben

6
您可以检测到超链接的点击,但无法确定用户是否进行了以下操作:
  • 尝试刷新页面。
  • 尝试关闭浏览器标签页。
  • 尝试关闭浏览器窗口。
  • 在 URL 地址栏中输入其他 URL 并按回车键。
所有这些操作都会在 window 上生成 beforeunload 事件,但没有更精确的关于事件的信息。
为了在执行上述操作时显示确认对话框,并在单击超链接时不显示它,请按照以下步骤操作:
  • beforeunload 事件监听器分配给 window,其返回确认文本作为字符串,除非特定变量(标志)设置为 true
  • click 事件分配给 document。检查是否已单击了 a 元素(event.target.tagName)。如果是,则将标志设置为 true
您还应通过将 submit 事件监听器分配给 document 来处理表单提交。
您的代码可能如下所示:

let disableConfirmation = false;
window.addEventListener('beforeunload', event => {
  const confirmationText = 'Are you sure?';
  if (!disableConfirmation) {
    event.returnValue = confirmationText; // Gecko, Trident, Chrome 34+
    return confirmationText;              // Gecko, WebKit, Chrome <34
  } else {
    // Set flag back to false, just in case
    // user stops loading page after clicking a link.
    disableConfirmation = false;
  }
});
document.addEventListener('click', event => {
  if (event.target.tagName.toLowerCase() === 'a') {
    disableConfirmation = true;
  }
});
document.addEventListener('submit', event => {
  disableConfirmation = true;
});
<p><a href="https://stacksnippets.net/">google.com</a></p>
<form action="https://stacksnippets.net/"><button type="submit">Submit</button></form>
<p>Try clicking the link or the submit button. The confirmation dialog won't be displayed.</p>
<p>Try reloading the frame (right click -> "Reload frame" in Chrome). You will see a confirmation dialog.</p>

请注意,在某些浏览器中,您需要在 beforeunload 监听器中使用 event.returnValue,而在其他浏览器中则使用 return 语句。
另请参阅 beforeunload 事件文档

3

我已经添加了额外的代码,用于处理窗口关闭后的进一步过程

let disableConfirmation = false;
window.addEventListener('beforeunload', event => {
  const confirmationText = 'Are you sure?';
  if (!disableConfirmation) {
    event.returnValue = confirmationText; // Gecko, Trident, Chrome 34+
    return confirmationText;              // Gecko, WebKit, Chrome <34
  } else {
    // Set flag back to false, just in case
    // user stops loading page after clicking a link.
    disableConfirmation = false;
  }
});

确认后,如果您想发送任何ajax请求并且已经使用了jquery,可以按照以下步骤操作:
 $(window).on('unload', function() {
   // async: false will make the AJAX synchronous in case you're using jQuery
   axios
     .get('ajax_url')
     .then(response => {});
 });

如果不使用jQuery,您可以使用navigator,它需要navigator库。
navigator.sendBeacon(url, data);

您可以从这里下载此库:https://github.com/miguelmota/Navigator.sendBeacon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接