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

时间:2009-05-04 19:11:22

标签: javascript onbeforeunload

在我正在处理的网络应用程序中,我正在捕获onBeforeUnload以询问用户确实是否想要退出。

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

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

我第一次希望在对话框显示时,SetTimeout调用不会触发,所以我可以设置一个短暂的超时时间,只有当用户选择留下时它才会触发。但是,在显示对话框时会超时执行,因此无效。

我尝试的另一个想法是在窗口/文档上捕获mouseMoves。显示对话框时,除了一个真正适用于我的情况的奇怪异常外,mouseMoves确实不会触发,因此也不起作用。

有人能想到其他方法吗?

谢谢!


(如果您好奇,捕获mouseMove不起作用的原因是我的页面中有一个IFrame,其中包含来自另一个域的网站。如果在卸载页面时,焦点位于IFrame,当对话框显示时,当鼠标从IFrame内部移动到外部时(至少在Firefox中),我得到MouseMove事件触发ONCE。这可能是一个bug,但是,它很可能会发生在我们的case,所以我不能用这个方法)。

4 个答案:

答案 0 :(得分:6)

我最终做的是挂钩我的文档的点击事件,一旦我收到点击,我认为用户已经停留。

这不是一个好的解决方案,在大多数情况下(如果你是一个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.
}

答案 1 :(得分:3)

过去几天我一直在网上研究这个问题,答案总是“不”,你无法确定用户是否留下或离开(除了你的应用程序退出工作的事实,用户离开)。我讨厌“不”的答案。我提出了以下实用程序。

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中检查它,但到目前为止它已经在所有三个中都没有打嗝。

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

答案 2 :(得分:0)

这是此类问题的热门话题,我知道具体情况(从8年前开始)无法使用此解决方案,因为它位于iFrame中,但未来任何人都可能会受到更多帮助通过以下答案而不是上面的答案:

你可以很容易地判断他们是否留下了身体事件监听器,我认为mousemove和keydown组合就足够了。

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

总而言之,它看起来像这样(你必须自己填写服务器的ajax调用):

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;
});

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

答案 3 :(得分:-7)

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

  

您确定要离开此页吗?

     

您已开始撰写或编辑帖子。

     

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

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