Javascript 检测在提示onBeforeUnload后用户是否停留

Javascript 检测在提示onBeforeUnload后用户是否停留,javascript,onbeforeunload,Javascript,Onbeforeunload,在我正在开发的一个web应用程序中,我正在捕获onBeforeUnload,询问用户是否真的想退出 现在,如果他决定留下来,我有很多事情想做。 我想弄明白的是他实际上选择了留下来 我当然可以声明一个SetTimeout为“x”秒,如果它触发,那么就意味着用户仍然在那里(因为我们没有卸载)。问题是用户可以随时决定是否留下来 我首先希望,当对话框显示时,SetTimeout调用不会触发,因此我可以设置一个短时间的超时,并且只有当用户选择留下时才会触发。但是,显示对话框时会触发超时do,因此无法工作

在我正在开发的一个web应用程序中,我正在捕获onBeforeUnload,询问用户是否真的想退出

现在,如果他决定留下来,我有很多事情想做。 我想弄明白的是他实际上选择了留下来

我当然可以声明一个SetTimeout为“x”秒,如果它触发,那么就意味着用户仍然在那里(因为我们没有卸载)。问题是用户可以随时决定是否留下来

我首先希望,当对话框显示时,SetTimeout调用不会触发,因此我可以设置一个短时间的超时,并且只有当用户选择留下时才会触发。但是,显示对话框时会触发超时do,因此无法工作

我尝试的另一个想法是在窗口/文档上捕获鼠标移动。当显示对话框时,mouseMoves确实不会启动,除了一个奇怪的异常,它确实适用于我的案例,所以这也不起作用

有人能想出其他的方法吗

谢谢



(如果您好奇,捕获mouseMove不起作用的原因是我的页面中有一个IFrame,其中包含来自另一个域的站点。如果在卸载页面时,焦点在IFrame内,而对话框显示,则当鼠标从IFrame内移到外时,我会触发一次mouseMove事件(至少在Firefox中是这样)。这可能是一个bug,但在我们的情况下,很可能会发生这种情况,所以我不能使用这种方法。)

为什么不使用StackOverflow所使用的方法,在这里你会得到一个弹出框,让你做出选择:

是否确实要导航到此页面之外

您已开始撰写或编辑文章

按“确定”继续,或按“取消”停留在当前页面


然后不管他们花了多长时间。如果他们单击一个按钮,他们就会离开。如果他们单击另一个按钮,他们就会留下来。

我最后做的是连接到我的文档的单击事件,一旦我收到一次单击,我就认为用户留下来了

这不是一个好的解决方案,在大多数情况下(如果你是一个DiggBar),你会有很多错误的否定(人们会留下来,你永远不会知道),但在我们的情况下,这是非常有意义的,因为人们与我们的网站,而不仅仅是框架网站进行了大量互动

本质上,我的代码就是这样做的

function OnBeforeUnload() {
    Event.observe(document, "click", UserStayed);
    if (IConsiderTheIFrameMightBeTryingToPopOut) {
        return "The site is trying to escape. Do you want to stay?";
    }
}

function UserStayed() {
Event.stopObserving(document, "click", UserStayed);
    // New we know the user is still with us for sure.
}

在过去的几天里,我一直在网上研究这个问题,答案总是“不”,你不能确定用户是留下来了还是离开了(除非用户离开后你的应用程序停止工作)。我讨厌“不”的答案。我提出了以下实用程序

var OnBeforeUnload = (function(){
    var
    FDUM = new Function,
    AFFIRM = function(){ return true; };

    var _reg = function(msg,opts){
        opts = opts || {};
        var
            pid = null,
            pre = typeof opts.prefire == 'function' ? opts.prefire : FDUM,
            callback = typeof opts.callback == 'function' ? opts.callback : FDUM,
            condition = typeof opts.condition == 'function' ? opts.condition : AFFIRM;

        window.onbeforeunload = function(){
            return condition() ? (pre(),setTimeout(function(){ pid = setTimeout(callback,20); },1),msg) : void 0; 
        }

        window.onunload = function(){ clearTimeout(pid); };

    }

    var _unreg = function(){ window.onbeforeunload = null;  }

    return {
        register : _reg,
        unregister : _unreg
    };

})();
所以,一个电话,比如

OnBeforeUnload.register('Hello!',{ 
    condition:function_that_returns_true_to_fire_event_false_to_ignore,
    prefire:function_to_call_on_page_exit_attempt, 
    callback:function_to_call_if_user_stays
});
将在处理程序中调用条件,以查看是否应激活。如果是,则在向用户显示弹出窗口(您可能希望暂停视频)之前执行prefire,并且仅当用户停留时才会发生回调

我的逻辑是在事件处理程序的主体中启动setTimeout。在用户按下其中一个按钮之前,setTimeout不会执行。在按下按钮之后,它会立即触发。在本例中,setTimeout不会调用回调,而是一个代理函数,该函数为回调执行另一个超时,延迟为20ms。如果用户停留如果没有,那么另一个处理程序会连接到onunload,它会清除调用回调的超时时间,确保回调永远不会被调用。我只有机会在Firefox、IE和Chrome中检查它,但到目前为止,它在这三个版本中都能正常工作

我希望这能帮助像我一样对这个问题的专利“否”感到沮丧的人们。这个代码可能并不完美,但我认为它在正确的轨道上。

这是这类问题的热门话题,我知道具体情况(从8年前开始)无法使用此解决方案,因为它位于iFrame中,但下面的答案可能比上面的答案更能帮助任何未来的参与者:

你可以很容易地判断出他们是否有身体事件监听器,我认为mousemove和keydown的组合应该足够了

要知道他们是否离开了,你需要一些服务器端的东西

总之,它看起来是这样的(您必须自己填写对服务器的ajax调用):


在服务器端,你将不得不使用一些丑陋的东西,一个计时器。做一堆尝试离开,并按照要求在停留时或在一分钟左右确认离开后删除它们。我无法想象任何情况下,知道用户离开是否比几分钟更具时间敏感性,但如果你有,请发表评论,因为e我想考虑一下。

我正在这样做。但我想在他们留下后做一些事情,除非他们留下。我基本上是让服务器知道他们留下了,这意味着卸载是由试图离开IFrame的东西引起的,而不是他们关闭窗口。这让我记录卸载的可能原因,这我以后可以做一些事情。但我只想在他们留下的情况下做这件事,我想确保他们在通知服务器之前留下来。因此,使用弹出窗口中的“我想留下”按钮点击触发“东西”的执行。也许我不理解这个问题。嗯,“我想留下”按钮属于浏览器,而不是我。我不能触摸它或对它做任何事情,它是一个标准对话框,我根本无法与之交互。据我所知,当用户决定留下来时,窗口/文档中没有触发的特定事件。好吧,假设它是一个确认()像这样使用的对话框,您可以使用confirm()调用的返回值来确定他们单击了哪个按钮。我不是100%确定,但我相信如果他们单击“确定”,您将返回true,如果他们单击“取消”,它将返回false。因此,您可以将其处理为t
window.addEventListener("beforeunload", function(event){
    //tell your server they are attempting to leave
    var tryLeaveID = serverLogAttempToLeave();

    //an element with giant letters and warning text, because you can no longer set text on the alert box
    var unsavedWarning = document.getElementById("unsavedChangesWarning");
    unsavedWarning.style.display = "block";

    var onStay = function() {
        //if they stay, tell your server so
        serverRevokeAttemptToLeave(tryLeaveID);
        unsavedWarning.style.display = "none";
        document.body.removeEventListener("mousemove", onStay);
        document.body.removeEventListener("keydown", onStay);
    }

    document.body.addEventListener("mousemove", onStay);
    document.body.addEventListener("keydown", onStay);


    var dialogText =  "undisplayed text";
    event.returnValue = dialogText;
    return dialogText;
});