window.onbeforeunload может срабатывать несколько раз - PullRequest
9 голосов
/ 08 ноября 2010

То, что вы не используете функцию, не означает, что она бесполезна.

Сеть Stack Exchange, GMail, Grooveshark, Yahoo!Mail и Hotmail используют приглашение onbeforeunload, чтобы предотвратить / предупредить пользователей о том, что они покидают страницу после того, как они начали что-то редактировать.О, да, почти каждая настольная программа , которая принимает сохраняемые данные пользовательского ввода, использует этот шаблон UX «запросить пользователя перед отъездом».


У меня есть функция, которая работает аналогичноэто:

window.onbeforeunload = function(){
    // only prompt if the flag has been set... 
    if(promptBeforeLeaving === true){
        return "Are you sure you want to leave this page?";
    }
}

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

Существуют ли надежные решения этой проблемы?


Примечание: следующее НЕ решение:

var alreadyPrompted = false;
window.onbeforeunload = function(){
    // only prompt if the flag has been set... 
    if(promptBeforeLeaving === true && alreadyPrompted === false){
        alreadyPrompted = true;
        return "Are you sure you want to leave this page?";
    }
}

, потому что пользователь может выбрать опцию «Оставаться на странице», что приведет к тому, что будущие onbeforeunload s перестанут работать.

Ответы [ 2 ]

6 голосов
/ 08 ноября 2010

Я думаю, вы могли бы сделать это с помощью таймера (setInterval), который запускается в обратном вызове onbeforeunload.Выполнение Javascript будет приостановлено, пока диалоговое окно подтверждения открыто, а затем, если пользователь отменяет синхронизированную функцию, она может сбросить переменную alreadyPrompted обратно в false и очистить интервал.

Просто идея.

Хорошо. Я сделал быстрый тест на основе вашего комментария.

<span id="counter">0</span>
window.onbeforeunload = function () {
   setInterval(function () { $('#counter').html(++counter); }, 1);
   return "are you sure?";
}
window.onunload = function () { alert($('#counter').html()) };

Между двумя обратными вызовами #counter никогда не превышал 2 (мс).Кажется, что использование этих двух обратных вызовов дает вам то, что вам нужно.

РЕДАКТИРОВАТЬ - ответ на комментарий:

Закрыть.Это то, о чем я думал

var promptBeforeLeaving = true,
    alreadPrompted = false,
    timeoutID = 0,
    reset = function () {
        alreadPrompted = false;
        timeoutID = 0;
    };

window.onbeforeunload = function () {
    if (promptBeforeLeaving && !alreadPrompted) {
        alreadPrompted = true;
        timeoutID = setTimeout(reset, 100);
        return "Changes have been made to this page.";
    }
};

window.onunload = function () {
    clearTimeout(timeoutID);
};
1 голос
/ 13 августа 2013

Я инкапсулировал ответы сверху в простую в использовании функцию:

function registerUnload(msg, onunloadFunc) {
    var alreadPrompted = false,
        timeoutID = 0,
        reset = function() {
            alreadPrompted = false;
            timeoutID = 0;
        };

    if (msg || onunloadFunc) { // register
        window.onbeforeunload = function() {
            if (msg && !alreadPrompted) {
                alreadPrompted = true;
                timeoutID = setTimeout(reset, 100);
                return msg;
            }
        };

        window.onunload = function() {
            clearTimeout(timeoutID);
            if (onunloadFunc) onunloadFunc();
        };
    } else { // unregister
        window.onbeforeunload = null;
        window.onunload = null;
    }
}

Для регистрации используйте:

registerUnload("Leaving page", function() { /* unload work */ });

Для отмены регистрации используйте:

registerUnload();

Надеюсь, это поможет ..

...