Как я могу переопределить диалог OnBeforeUnload и заменить его своим собственным?


347

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

window.onbeforeunload=handler

Это работает, но вызывает диалоговое окно по умолчанию с раздражающим стандартным сообщением, которое оборачивает мой собственный текст. Мне нужно либо полностью заменить стандартное сообщение, чтобы мой текст был чистым, либо (что еще лучше) заменить весь диалог модальным диалогом с использованием jQuery.

Пока что я потерпел неудачу, и я не нашел никого, кто, кажется, имеет ответ. Это вообще возможно?

Javascript на моей странице:

<script type="text/javascript">   
   window.onbeforeunload=closeIt;
</script>

Функция closeIt ():

function closeIt()
{
  if (changes == "true" || files == "true")
  {
      return "Here you can append a custom message to the default dialog.";
  }
}

Используя jQuery и jqModal, я пробовал подобные вещи (используя пользовательский диалог подтверждения):

$(window).beforeunload(function() {
        confirm('new message: ' + this.href + ' !', this.href);
        return false;
    });

что также не работает - я не могу связываться с событием beforeunload.


1
Можете ли вы привести пример вашего текущего кода и что он производит?
Оуэн

Оуэн прав. И причина этого заключается в безопасности. Предотвращение выгрузки страницы полезно в веб-формах и тому подобном, но злоумышленник может легко использовать ее, чтобы обмануть пользователя, оставаясь на странице. Вот почему веб-браузеры реализуют стандартное сообщение и имеют этот механизм для вставки пользовательского текста.
pluckyglen

см. здесь для получения дополнительной информации: stackoverflow.com/questions/140460
Бен Макинтайр

Дополнительная информация: stackoverflow.com/questions/7389554/crossbrowser-onbeforeunload/…
Элиос

1
не представляется возможным в хроме, ссылка: stackoverflow.com/questions/37782104/...
Abhijeet

Ответы:


301

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

window.onbeforeunload = function() {
    return 'You have unsaved changes!';
}

Вот ссылка на это от Microsoft:

Когда строка присваивается свойству returnValue файла window.event, появляется диалоговое окно, которое дает пользователям возможность остаться на текущей странице и сохранить назначенную ей строку. Выражение по умолчанию, которое появляется в диалоговом окне «Вы уверены, что хотите отойти от этой страницы? ... Нажмите OK, чтобы продолжить, или Отмена, чтобы остаться на текущей странице.», Невозможно удалить или изменить.

Кажется, проблема в следующем:

  1. Когда onbeforeunloadвызывается, он будет принимать возвращаемое значение обработчика какwindow.event.returnValue .
  2. Затем он будет анализировать возвращаемое значение как строку (если оно не равно нулю).
  3. Поскольку falseон анализируется как строка, диалоговое окно будет запущено, которое затем передаст соответствующий true/ false.

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

Дополнительные примечания по jQuery:

  • Установка события в jQuery может быть проблематичной, так как это позволяет происходить и другим onbeforeunloadсобытиям. Если вы хотите, чтобы событие unload происходило, я бы остановился на обычном JavaScript.
  • У jQuery нет ярлыка, onbeforeunloadпоэтому вам придется использовать общий bindсинтаксис.

    $(window).bind('beforeunload', function() {} );

Изменить 09/04/2018 : пользовательские сообщения в диалогах onbeforeunload устарели начиная с chrome-51 (см. Примечание к выпуску )


20
Я обнаружил, что приведенный в конце пример JQuery не работает в Firefox. Вместо этого придерживайтесь простого способа: window.onbeforeunload = function () {...}
jb.

21
Просто обратите внимание, что Firefox был недавно изменен, так что текст в диалоговом окне даже не может быть изменен: bugzilla.mozilla.org/show_bug.cgi?id=588292
Дэвид Хаммонд,

15
Но как тогда Facebook предоставляет настраиваемое диалоговое окно? Например, перейдите на страницу сообщений, ответьте на сообщение вашего друга, а затем, прежде чем нажать «Отправить», попробуйте нажать другую ссылку. вы увидите всплывающее диалоговое окно
Varun

20
@Varun - старые новости, но Facebook, возможно, помещает обработчики в событие click всех их якорей, но если вы переписываете URL в браузере или закрываете окно, он возвращается к стандартному методу, который они не могут контролировать.
Tabloo Quijico

1
@Varun Я также удивлен, что этот ответ, который невозможен, помечен как ответ и имеет 150 голосов ... Только что понял, пользовательское сообщение FB доступно только через ссылки внутри их сайта. Нет, если вы просто уйдете ...
Себастьян Ришер

28

Что сработало для меня, используя jQuery и протестировано в IE8, Chrome и Firefox, так это:

$(window).bind("beforeunload",function(event) {
    if(hasChanged) return "You have unsaved changes";
});

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


Интересно, event.returnValueчто это единственный «одобренный» метод в IE. IE продолжает: «Значение этого свойства имеет приоритет перед значениями, возвращаемыми функцией, например, с помощью оператора возврата Microsoft JScript». .. было бы неплохо увидеть гарантированную корреляцию между return(из события) и event.returnValue..

21

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

Я использовал Boxy вместо стандартного диалога jQuery, он доступен здесь: http://onehackoranother.com/projects/jquery/boxy/

$(':input').change(function() {
    if(!is_dirty){
        // When the user changes a field on this page, set our is_dirty flag.
        is_dirty = true;
    }
});

$('a').mousedown(function(e) {
    if(is_dirty) {
        // if the user navigates away from this page via an anchor link, 
        //    popup a new boxy confirmation.
        answer = Boxy.confirm("You have made some changes which you might want to save.");
    }
});

window.onbeforeunload = function() {
if((is_dirty)&&(!answer)){
            // call this if the box wasn't shown.
    return 'You have made some changes which you might want to save.';
    }
};

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

Я вырезал код, так что это может не работать как есть.


return 'Вы внесли некоторые изменения, которые вы можете сохранить.' не работал для меня. Мне нужно было сохранить сообщение в переменной сказать «warning_message», и я вернул warning_message. Тогда только у меня получалось!
Суганья

Вы тестировали в IE, Chrome, Firefox?
Kiquenet

9

1) Используйте перед загрузкой, а не загрузкой.

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

3) Если вы используете onbeforeunload, вы можете запустить ajax-вызов в своем обработчике unbeforeunload, чтобы привести в порядок сервер, но он должен быть синхронным, и вам придется ждать и обрабатывать ответ в своем обработчике onbeforeunload (все еще соблюдая условие (2) выше). Я делаю это, и это прекрасно работает. Если вы делаете синхронный вызов ajax, все задерживается до тех пор, пока ответ не вернется. Если вы делаете асинхронный ответ, думая, что вам не нужен ответ от сервера, выгрузка страницы продолжается, и ваш процесс ajax прерывается этим процессом - включая удаленный скрипт, если он выполняется.


Просто к сведению тех, кто читает это ... Chrome не поддерживает синхронные вызовы AJAX в unbeforeunload
morganwebdev

4

Попробуйте разместить return;вместо сообщения ... это работает большинство браузеров для меня. (Это только действительно мешает подаркам диалога)

window.onbeforeunload = function(evt) {            
        //Your Extra Code
        return;
}

3
возвращение ноль будет препятствовать открытию диалога
Бретт Вебер

1
return null НЕ помешает открытию диалога. Я попробовал это в Chrome, и это не так.
Рэй

2
Я могу подтвердить комментарий Рэя в IE. Возврат nullоткроет диалог с текстом «ноль». Однако return void(0);не откроет диалог.
MCattle

1
Не помещая никакого оператора возврата в функцию beforeunload, диалог не откроется.
OuuGiii


3

Вы можете определить, какая кнопка (ок или отмена) нажата пользователем, потому что функция onunload вызывается только тогда, когда пользователь выбирает покинуть страницу. Хотя в этой функции возможности ограничены, потому что DOM рушится. Вы можете запустить javascript, но ajax POST ничего не делает, поэтому вы не можете использовать этот метод для автоматического выхода из системы. Но для этого есть решение. Window.open ('logout.php') выполняется в функции onunload, поэтому пользователь выходит из системы с открытием нового окна.

function onunload = (){
    window.open('logout.php');
}

Этот код вызывается, когда пользователь покидает страницу или закрывает активное окно и пользователь выходит из системы с помощью logout.php. Новое окно закрывается сразу, когда выход php состоит из кода:

window.close();

Вы можете использовать синхронный пост в функциях beforeunload и unload. Особенно, если вам нужны данные обратно с сервера. Любой асинхронный код в этих блоках может не завершиться к моменту выгрузки страницы.
Джемилойи

3

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

Ниже приведен код решения, который я нашел и написал на своей главной странице.

function closeMe(evt) {
    if (typeof evt == 'undefined') {
        evt = window.event; }
    if (evt && evt.clientX >= (window.event.screenX - 150) &&
        evt.clientY >= -150 && evt.clientY <= 0) {
        return "Do you want to log out of your current session?";
    }
}
window.onbeforeunload = closeMe;


1

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

$(window).one("beforeunload", BeforeUnload);

почти уверен, что это .on ("beforeunload"
Серджиу Миндрас

2
@SergiuMindras нет, это .one()- это прикрепляет прослушиватель событий для прослушивания события, которое происходит только один раз: «Присоединить обработчик к событию для элементов. Обработчик выполняется не более одного раза для каждого элемента для каждого типа события». api.jquery.com/one
Шон Кендл

0

Угловой 9 подход:

constructor() {
    window.addEventListener('beforeunload', (event: BeforeUnloadEvent) => {
     if (this.generatedBarcodeIndex) {
      event.preventDefault(); // for Firefox
      event.returnValue = ''; // for Chrome
      return '';
     }
     return false;
    });
   }

Поддержка браузеров и удаление пользовательских сообщений:

  • Хром убрал поддержку пользовательского сообщения в версии 51 мин
  • Опера убрала поддержку пользовательского сообщения в версии 38 мин.
  • Firefox удалил поддержку пользовательского сообщения в версии 44.0 мин.
  • Safari убрал поддержку пользовательского сообщения в версии 9.1 мин.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.