Перехватить событие выхода из страницы

117

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

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

Gmail делает это очень похожим образом. Например, составьте новое электронное письмо, начните вводить текст в теле сообщения и введите новое место в адресной строке (скажем, twitter.com или что-то в этом роде). Появится запрос "Вы уверены?"

Идеи, как это воспроизвести? Я нацелен на IE8, но также хотел бы быть совместим с FF и Chrome.

Крис Балланс
источник

Ответы:

154

Подобно ответу Гомми, но он также поддерживает старые версии IE и Firefox.

window.onbeforeunload = function (e) {
  var message = "Your confirmation message goes here.",
  e = e || window.event;
  // For IE and Firefox
  if (e) {
    e.returnValue = message;
  }

  // For Safari
  return message;
};
Эли Грей
источник
1
Не могли бы вы объяснить первую строку (var message = ...)? Я не знаю, что делают эта запятая и второе выражение.
mtmurdock
7
@mtmurdock Это просто синтаксис Javascript для объявления нескольких переменных. var foo, bar;совпадает сvar foo; var bar;
T Nguyen
4
@mtmurdock, второй оператор " var e = e || window.event;" означает установить e равным параметру e (если это правда) или window.event, если не правда. Это не будет правдой, если параметр e равен нулю.
T Nguyen
3
@Blieque addEventListener не поддерживается в IE8. Не редактируйте ответы людей, даже не прочитав вопрос.
Эли Грей
2
Больше не работает в Chrome (устарело): developers.google.com/web/updates/2016/04/…
Micha Schwab
25

См. Эту статью. Функция, которую вы ищете, это функция onbeforeunload

образец кода:

  <script language="JavaScript">
  window.onbeforeunload = confirmExit;
  function confirmExit()
  {
    return "You have attempted to leave this page.  If you have made any changes to the fields without clicking the Save button, your changes will be lost.  Are you sure you want to exit this page?";
  }
</script>
jantimon
источник
2
Есть ли способ определить, что пользователь выбрал вариант «Покинуть эту страницу», а не «Остаться на этой странице»?
Шилпа Сони
@ShilpaSoni вы вскоре получите последующее событие выгрузки, developer.mozilla.org/en-US/docs/Web/API/Window/unload_event, но я не думаю, что есть синхронный способ.
scipilot
6

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

window.onbeforeunload=function(e){
  // only take action (iterate) if my SCHEDULED_REQUEST object contains data        
  for (var key in SCHEDULED_REQUEST){   
    postRequest(SCHEDULED_REQUEST); // post and empty SCHEDULED_REQUEST object
    for (var i=0;i<1000;i++){
      // do something unnoticable but time consuming like writing a lot to console
      console.log('buying some time to finish saving data'); 
    };
    break;
  };
}; // no return string --> user will leave as normal but data is send to server

Изменить: см. Также Synchronous_AJAX и как это сделать с помощью jquery

Remi
источник
Мне нравится эта альтернатива всплывающему окну. Спасибо за предложение, Реми.
Крис Балланс
2
это не имеет абсолютно никакого смысла -1. javascript не связан с потоками, вы делаете postRequest, а затем приостанавливаете вычисление сайта, не позволяя никому ничего делать (включая ваш postRequest, который тем временем уже был отправлен до паузы вычислений).
fmsf 04
И именно поэтому он работает: действительно, пост-запрос был отправлен до паузы вычислений, но эта небольшая блокировка страницы до того, как она фактически останется, обеспечивает достаточно времени для клиента браузера (не javascript), чтобы действительно правильно завершить отправку этого запроса. , Я заметил, что когда я только отправляю запрос (без блокировки) и сразу же покидаю страницу, запрос не всегда отправляется.
Remi
6
Я бы не стал использовать это в производстве. console.log не является кроссбраузерным; каждый postRequest страдает от задержки предыдущих (что также означает, что страница будет висеть там на время вашего цикла * запланированных запросов); запросы не запускаются параллельно; у вас нет гарантии, что вы действительно отправите свои запросы. Если бы мне пришлось столкнуться с этой проблемой, я бы использовал синхронный запрос ajax, если есть только один запрос. С несколькими запросами я бы использовал асинхронные запросы ajax и цикл, который проверяет результаты (успех или ошибку) обратных вызовов запросов.
Framp
Я не знал, что console.log не является кроссбраузерным, и синхронный запрос Ajax действительно должен быть предпочтительным решением (для одного запроса). Упомянутый SCHEDULED_REQUESTявляется объектом, который накапливает любую несрочную информацию, которая должна быть отправлена ​​на сервер, например, буфер данных, эффективно объединяя несколько запросов в один (конечно, URL-адреса этих запросов одинаковы). Использование синхронного запроса Ajax перед выгрузкой должно решить проблему кроссбраузерности, как вы сказали. Спасибо за ценный комментарий!
Реми
0

У меня есть пользователи, которые не заполняли все необходимые данные.

<cfset unloadCheck=0>//a ColdFusion precheck in my page generation to see if unload check is needed
var erMsg="";
$(document).ready(function(){
<cfif q.myData eq "">
    <cfset unloadCheck=1>
    $("#myInput").change(function(){
        verify(); //function elsewhere that checks all fields and populates erMsg with error messages for any fail(s)
        if(erMsg=="") window.onbeforeunload = null; //all OK so let them pass
        else window.onbeforeunload = confirmExit(); //borrowed from Jantimon above;
    });
});
<cfif unloadCheck><!--- if any are outstanding, set the error message and the unload alert --->
    verify();
    window.onbeforeunload = confirmExit;
    function confirmExit() {return "Data is incomplete for this Case:"+erMsg;}
</cfif>
Гордон
источник