【问题标题】:Trigger an event when user navigates away当用户离开时触发事件
【发布时间】:2013-04-02 06:13:08
【问题描述】:

当用户关闭他的窗口/选项卡或通过单击链接导航离开时,我需要在 PHP 页面上调用其中包含几行代码的 JavaScript/jQuery 函数。我试过onbeforeunload 函数,但只有return "blah blah blah;" 部分执行,其他所有内容都被忽略。我也尝试过 jQuery 的 .unload 方法,但由于某种原因,这段代码没有运行。

$(window).unload(function() {
    alert('blah blah blah');
});

请提出替代方案。谢谢..

【问题讨论】:

  • 卸载时要做什么?
  • 我需要对 PHP 进行 Ajax 调用以取消设置会话变量。
  • navigates away by clicking a link 这表明您必须在文档上绑定卸载
  • $(window).on('beforeunload', function() { ... });,但是你不能阻止页面卸载,所以你只有很短的时间去做事情,问题是你想做的事情是否也需要长,然后页面卸载。

标签: javascript jquery events


【解决方案1】:

这是一个简单的工作示例。无论您来自unload 回调的return 都将显示在浏览器弹出确认中。

卸载前发送 Ajax 请求的工作示例 http://jsfiddle.net/alexflav23/hujQs/7/

最简单的方法:

window.onbeforeunload = function(event) {
    // do stuff here
    return "you have unsaved changes. Are you sure you want to navigate away?";
};

在 jQuery 中:

$(window).on("beforeunload", function() {
    $.ajax("someURL", {
        async: false,
        data: "test",
        success: function(event) {
             console.log("Ajax request executed");
        }
    });
    return "This is a jQuery version";
});

查看浏览器的“网络”选项卡。您将看到请求是如何按照您的意愿发送的。只需发送适当的数据。

请记住,所有触发的操作都必须是同步的,因此您只能发出同步的 ajax 请求。但是,以上内容对于任何目的都不是完全可靠的。

选择定期将用户数据备份到localStorage 并自动与服务器同步。保留window.onbeforeunload 只是作为额外的预防措施,而不是作为主要机制。众所周知,它会导致问题。

【讨论】:

  • 这不起作用。无论用户是否确认警告,总是调用 beforeunload。我需要运行一些清理,但我只想在用户实际导航离开时运行清理。我该怎么做?
  • @JohnHenckel 没有办法做到这一点。
  • @apscience,谢谢。似乎这是浏览器规范中的一个缺陷。例如,我想制作一个网页来编辑数据库中的一行,并且我想锁定该行以防止其他用户更改它。我找到的唯一解决方案是每隔几秒向服务器发送一次心跳,以便服务器知道何时解锁。但是,这有一个严重的缺陷,因为当任何“确认”框打开时,JS 引擎都会暂停,因此心跳停止,即使用户仍在编辑!也许有一天浏览器会取代操作系统,但现在它作为一个应用平台很糟糕!
  • 很抱歉迟到了,但要做到这一点,您可以使用onbeforeunloadonunload 的组合。您在 onbeforeunload 的返回和 onunload 中的任何清理中显示警告文本。如果您选择了留置选项,则不会调用 onunload。确保在 onbeforunload 和 onunload 中使用同步调用。如果您需要帮助,可以提供一些示例。
  • @foxont​​herock 2013 回答,这可能不再是最新的了。
【解决方案2】:

这是一个老问题,但我想分享一种替代方法,该方法具有高一致性的好处:

建立到服务器的 WebSocket 连接,当客户端离开时,WebSocket 连接将被关闭。在服务器端,您可以在回调中检测关闭的连接并在服务器上运行您需要的任何代码。

在页面卸载时执行 Javascript 通常是不可靠的(如另一个答案中所述),因为它本质上与用户的意图不一致。这种方法总能奏效,尽管实施起来确实有点麻烦。

这确实将“离开前运行”代码的上下文从客户端更改为服务器端,但我想在大多数情况下,差异是无关紧要的。在客户端离开您的页面之前您想在客户端运行的任何内容都可能不会改变客户端看到的任何内容,因此在服务器端运行它可能没问题。如果您需要从客户端获取特定数据,您可以通过 WebSocket 将其发送到服务器。

我能想到的唯一可能导致意外行为的情况是,如果用户在没有实际导航的情况下丢失了 WS 连接,例如他们失去了互联网或让他们的电脑进入睡眠状态。这是否重要可能在很大程度上取决于您尝试执行的代码类型。

【讨论】:

    【解决方案3】:

    在我的许多项目中,这里提到的方法是不稳定的对我有用的唯一方法是将事件绑定为 body 元素上的原始属性

    <body onunload="my_function_unload()">
    

    jQuery 方法:

    $('body').attr('onunload', 'my_function_unload()');
    

    来自 iframe:

    <body onunload="window.parent.my_function_unload()">
    

    jQuery 方法:

    $('<iframe />').load(function(){
        $body = $(this).contents().find('body');
        $body.attr('onunload', 'window.parent.my_function_unload()');
    }
    

    另外,重要,属性中没有参数,并且函数必须在全局窗口范围内,否则什么也不会发生。

    例如,常见错误如果您的my_function_unload() 被包裹在;( function( $ ) {...$(document).ready(function(){... 中,则my_function_unload() 必须在该私有范围之外。然后不要忘记使用jQuery 而不是$ 前缀。 (以 Wordpress 为例)

    【讨论】:

      【解决方案4】:

      这有点让人头疼,因为 Chrome 至少在版本 92.0.4515.131 中似乎将安全螺丝固定在您可以在beforeunload 中逃脱的东西上。例如,我无法发出同步 ajax 请求。

      如果用户有任何机会返回您的网站,您可以等到那时处理他们关闭窗口的问题(这在我的用例中确实有效),请知道设置 cookie 目前似乎是公平的游戏在beforeunload 事件期间。甚至在我关闭浏览器时也可以使用。它涵盖了除了重启计算机之外的大部分内容。

      这是一个参考示例(getCookiethis SO question 被盗):

      function setCookie(name, value) {
          document.cookie =
              '{0}={1};expires=Fri, 31 Dec 9999 23:59:59 GMT;path=/;SameSite=Lax'
                  .replace("{0}", name)
                  .replace("{1}", value);
      }
      
      // https://stackoverflow.com/a/25490531/1028230
      function getCookie(cookieName) {
          var b = document.cookie.match('(^|;)\\s*' + cookieName + '\\s*=\\s*([^;]+)');
          return b ? b.pop() : '';
      }
      
      window.addEventListener('beforeunload', function (e) {
          console.log('cookie value before reset: ' + getCookie('whenItHappened'));
      
          var now = +new Date();
          console.log("value to be set: " + now);
          setCookie('whenItHappened', now);
      
          return "some string if you want the 'are you sure you want to leave' dialog to appear";
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-25
        • 2016-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多