Определение того, остался ли пользователь после запроса onBeforeUnload - PullRequest
9 голосов
/ 04 мая 2009

В веб-приложении, над которым я работаю, я собираю onBeforeUnload, чтобы спросить пользователя, действительно ли он хочет выйти.

Теперь, если он решит остаться, я бы хотел сделать несколько вещей. Я пытаюсь понять, что он на самом деле решил остаться.

Конечно, я могу объявить SetTimeout на «х» секунд, и если это произойдет, то это будет означать, что пользователь все еще там (потому что мы не были выгружены). Проблема в том, что пользователь может в любое время решить, остаться ему или нет ...

Сначала я надеялся, что во время отображения диалога вызовы SetTimeout не будут срабатывать, поэтому я мог установить тайм-аут на короткое время, и он срабатывал только в том случае, если пользователь решил остаться. Однако тайм-ауты do срабатывают, пока отображается диалоговое окно, поэтому это не работает.

Еще одна идея, которую я попробовал, - захват мышиных движений в окне / документе. Хотя диалоговое окно отображается, mouseMoves действительно не запускаются, за исключением одного странного исключения, которое действительно применимо к моему случаю, поэтому оно тоже не будет работать.

Кто-нибудь может придумать другой способ сделать это?

Спасибо!


(Если вам любопытно, причина захвата mouseMove не работает, потому что у меня есть IFrame на моей странице, содержащий сайт из другого домена. Если во время выгрузки страницы фокус находится в пределах IFrame, пока отображается диалоговое окно, затем я получаю событие MouseMove, запускающееся ОДИН РАЗ, когда мышь перемещается изнутри IFrame наружу (по крайней мере, в Firefox). Это, вероятно, ошибка, но, тем не менее, очень вероятно, что это произойдет случай, поэтому я не могу использовать этот метод).

Ответы [ 4 ]

6 голосов
/ 18 июня 2009

В итоге я подключился к событию click для моего документа, и как только я получил щелчок, я решил, что пользователь остался.

Это не хорошее решение, в большинстве случаев (если вы 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.
}
3 голосов
/ 06 марта 2013

Я изучал этот вопрос в Интернете в течение последних нескольких дней, и ответ, неизменно, «нет», вы не можете точно сказать, что пользователь остался или ушел (кроме факта, что ваше приложение перестает работать, если пользователь уходит). Я ненавижу "нет" ответы. Я придумал следующую утилиту.

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

условие будет вызвано в обработчике, чтобы увидеть, должно ли оно активироваться или нет. Если это так, предварительный запуск выполняется до того, как пользователю будет показано всплывающее окно (может потребоваться приостановить воспроизведение видео), и обратный вызов произойдет ТОЛЬКО, если пользователь останется.

Моя логика заключалась в том, чтобы инициировать setTimeout в теле обработчика событий. SetTimeout не будет выполняться, пока пользователь не нажмет одну из кнопок. После того, как они это делают, он немедленно срабатывает. В этом случае setTimeout вызывает не обратный вызов, а прокси-функцию, которая выполняет другой тайм-аут для обратного вызова с задержкой 20 мс. Если пользователь остается на странице, выполняется обратный вызов. Если нет, то к onunload присоединяется другой обработчик, который очищает тайм-аут, который вызовет обратный вызов, гарантируя, что обратный вызов никогда не вызывается. У меня была возможность проверить это только в Firefox, IE и Chrome, но пока все работало без сбоев.

Я надеюсь, что это помогает людям, столь же разочарованным, как и я, согласно патенту «нет», универсально предоставленному этому вопросу. Этот код может быть не идеальным, но я думаю, что он на правильном пути.

0 голосов
/ 19 июля 2017

Это самый популярный вопрос для этого типа вопросов, и я знаю, что конкретный случай (с 8 лет назад) не мог использовать это решение, потому что это было в iFrame, но всем будущим посетителям, вероятно, будет больше помочь ответом ниже, чем выше:

Вы можете легко сказать, остались ли они со слушателем событий тела, я думаю, что сочетания мыши и перемещения должно быть достаточно.

Чтобы узнать, ушли ли они, вам понадобятся некоторые вещи на стороне сервера.

В целом, это будет выглядеть примерно так (вам придется самостоятельно заполнять вызовы 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;
});

На стороне сервера вам придется использовать что-то уродливое, таймер. Сделайте пачку попыток уйти и удалите их либо по запросу во время пребывания, либо через минуту или около того в качестве подтвержденного отпуска. Я не могу представить ни одного случая, когда знание того, что пользователь ушел, более чувствительно ко времени, чем несколько минут, но если оно у вас есть, прокомментируйте, потому что я хотел бы подумать об этом.

0 голосов
/ 05 мая 2009

Почему бы просто не использовать метод, который делает StackOverflow, где вы получаете всплывающее окно, которое позволяет вам сделать выбор:

Вы уверены, что хотите уйти с этой страницы?

Вы начали писать или редактировать сообщение.

Нажмите OK, чтобы продолжить, или Отмена, чтобы остаться на текущей странице

Тогда не имеет значения, сколько времени они займут. Если они нажимают одну кнопку, они уходят. Если они нажмут на другую, они останутся.

...