Я изучал этот вопрос в Интернете в течение последних нескольких дней, и ответ, неизменно, «нет», вы не можете точно сказать, что пользователь остался или ушел (кроме факта, что ваше приложение перестает работать, если пользователь уходит). Я ненавижу "нет" ответы. Я придумал следующую утилиту.
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, но пока все работало без сбоев.
Я надеюсь, что это помогает людям, столь же разочарованным, как и я, согласно патенту «нет», универсально предоставленному этому вопросу. Этот код может быть не идеальным, но я думаю, что он на правильном пути.