'onbeforeunload'触发两次

5

当用户离开页面或关闭窗口时,我想发送一个ajax请求。
以下是我的代码:

<script type="text/javascript">
    function sendajax(){
        $.ajax({
          url: "someurl",
          data: mydata,
          async : false
        });   
    }
</script>
    <script type="text/javascript">
     window.onbeforeunload=function(){sendajax();};
</script>   

当事件发生时,该事件会触发两次。
为什么会发生这种情况?
我知道可以通过添加变量 var ajaxSent=true; 来防止它发生,但也许有一种更简洁的方法可以实现呢?

更新:
我用其他代码替换了 sendajax 函数的内容(不发送 ajax 请求),发现问题不在于 ajax。它仍然会进入函数两次。


页面上有任何iframe吗? - beeglebug
不,这是一个测试页面的一部分,只包含一些文本和一个链接。 - lvil
你能提供一个例子吗?另外,你在哪个浏览器中看到这种情况发生? - beeglebug
这是头标签后的唯一代码:'<body> sssssss <a href="http://www.www.ww">abc</a> </body>' 我已经在Ubuntu上尝试了Chrome16和Firefox3.6。 - lvil
1
奇怪,我无法在任何浏览器中在我的Windows 7机器上多次触发事件。如果您尝试这个模仿您代码的jsFiddle:http://jsfiddle.net/rWKdR/,它会发生两次吗? - beeglebug
显示剩余2条评论
6个回答

6

根据您的编辑和评论中的代码,看起来这可能只是由于您点击离开页面的损坏链接造成的。

给定以下代码:

<script>
    function doSomething() { console.log('onbeforeunload fired'); }
    window.onbeforeunload = doSomething;
</script>
<a href="garbage">link A</a>
<a href="http://google.com">link B</a>

如果我点击链接A,会出现两个控制台日志条目,如果我点击链接B,只会出现一个。
看起来这可能是浏览器处理其内部“此网页未找到”页面的怪异方式导致您的页面在显示消息之前被刷新并关闭,留下了两个onbeforeunload事件发生的情况。

我发现beforeunload事件的行为在IE文档模式方面存在显著差异(特别是关于它被调用的次数)。较新和更标准的行为比旧的向后兼容(IE10)的行为触发频率更低。 - BlueMonkMN

3

我曾经遇到过同样的问题,花了一些时间才理解并解决了它,下面分享一下案例细节:

在我们的模板中有一个自定义JS脚本来操作菜单。这导致在IE / EDGE浏览器中,只有在点击菜单链接时卸载(unload)事件会触发两次,而其他链接则不会。

最终我们阻止了这些链接的事件传播,问题得以解决。

$('.SELECTOR a[href^="http://"]').on('click', function(e){
    e.stopPropagation();
});

这是你的应用程序中的一个特定错误,因此在Google上找不到太多信息。


0
在React/Next js中,我也遇到了同样的问题。我的beforeunload事件会触发3-4次。我只需通过添加removeEventListener来解决这个问题。

现在它只会触发1次。

useEffect(() => {
        console.log("zzzzzzzzzzzzz 003 ",formLoadingState)

        const handleBeforeUnload = (event) => {
            console.log("zzzzzzzzzzzzz 033 ",formLoadingState)

            if (formLoadingState) {
                event.preventDefault()
                event.returnValue = ''
            }
        }
        
        window.addEventListener('beforeunload', handleBeforeUnload)
        return () => {
            window.removeEventListener('beforeunload', handleBeforeUnload)
        }
    }, [formLoadingState])

0

同意AlonMichaeli的概念。 在我的应用程序中,锚点标签与几个spans一起包装在一个div中。当在脏页面上单击Anchor时,会出现几个“离开站点”的通知。 如果单击menuItem的任何其他部分(div或spans),它就可以正常工作。 因此,在自定义JavaScript方法中,我仅在单击锚点标签时添加了stopped propagation和preventDefault。不知何故,在这种情况下,preventDefault是必要的。

function menuItemClicked(event: JQueryEventObject) {
  var item = $(event.target);
  if (item.is(".anchor-item")) { 
    event.stopPropagation();
    event.preventDefault();
  }
  href = item.closest(".anchor-item").attr("href");
  if (!event.ctrlKey && href) {
    window.location.href = href;
  }
}

0
你可以尝试以下代码:
<script type="text/javascript"><br>
     window.onbeforeunload=function sendajax(){<br>
        $.ajax({<br>
          url: "someurl",<br>
          data: mydata,<br>
          async : false<br>
        });<br>
};<br>
</script>

或者你可以在某个地方定义sendajax() {},然后像这样使用它:onbeforeunload = "sendajax()"而不是onbeforeunload = "function () { sendajax() }"


内联函数命名的目的是什么?之后无法引用sendajax,似乎有些多余。 - beeglebug
@beeglebug:你是对的,这种情况只需要使用一次函数时才会出现。 如果你想要在其他地方使用这个函数,应该定义它并像这样调用:onbeforeload ="sendajax()",而不是 onbeforeload ="function(){ sendajax() }", 因为在后者中,sendajax 被调用了两次,首先在定义该函数时(注意不是 sendajax()),然后在定义之后外部函数本身被调用一次,再次调用该 sendajax()。 - me_digvijay
我已经将 'window.onbeforeunload=function(){sendajax();};' 更改为 'window.onbeforeunload="sendajax()";',然后更改为 'window.onbeforeunload="sendajax();";' 和 'window.onbeforeunload="sendajax";'。但以上任何一种方式都没有起作用,该函数根本没有执行。 - lvil
你也可以将函数称为window.onbeforeunload = sendajax;,并且在定义时必须传递一个事件参数到sendajax函数中,例如function sendajax(e) {}。 - me_digvijay

0

beforeUnload是可取消的

我知道这篇文章很旧了,但从Chrome页面生命周期API文档中可以看出,浏览器偶尔会部分卸载页面以节省资源。https://developers.google.com/web/updates/2018/07/page-lifecycle-api beforeUnload不能保证页面被关闭。特别是在Android设备上锁屏时经常发生。

我找到了一个jsfiddle,你可以测试一下https://jsfiddle.net/ov6b9pdL/。在Chrome Android上锁定屏幕5-10分钟,你会发现beforeUnload被触发,甚至没有关闭选项卡。

$(document).ready(function() {
    window.addEventListener('beforeunload', showLoader);
});

var showLoader = function() {
    $('#loader').show();
};

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