Определение того, остался ли пользователь после запроса onBeforeUnload

StackOverflow https://stackoverflow.com/questions/821481

  •  03-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

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

Спасибо!


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

Это было полезно?

Решение

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

Это не очень хорошее решение, в большинстве случаев (если вы копатель) у вас будет много ложноотрицательных результатов (люди останутся, а вы никогда об этом не узнаете), но в нашем случае это имело смысл, потому что люди активно взаимодействуют с нашим сайтом, а не только с оформленными сайтами.

По сути, мой код делает это...

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

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

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

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

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

Вы можете легко определить, остались ли они с прослушивателем событий body, я думаю, что комбинированных 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;
});

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top