При нажатии кнопки «Назад» происходит событие кросс-браузерной загрузки?

185

Для всех основных браузеров (кроме IE) onloadсобытие JavaScript не запускается при загрузке страницы в результате операции кнопки «Назад» - оно запускается только при первой загрузке страницы.

Может кто-нибудь указать мне пример кросс-браузерного кода (Firefox, Opera, Safari, IE, ...), который решает эту проблему? Я знаком с pageshowсобытием Firefox, но, к сожалению, ни Opera, ни Safari не реализуют это.

Билл
источник
6
Это не проблема - он позволяет быстро загружать веб-страницу, когда пользователь нажимает кнопку «Назад». Смотрите мой ответ ниже для деталей. Предлагаемые здесь обходные пути делают веб-страницу более раздражающей для пользователя, поскольку перемещение назад / вперед медленнее.
Николай
2
@romkyns: ваш комментарий не имеет отношения к этому вопросу. Когда браузеры не восстанавливают состояние JS / DOM, они запускают событие загрузки.
Николай
Кнопка возврата истории iOS 5+ здесь решена stackoverflow.com/a/12652160/1090395
Младен Янджетович

Ответы:

117

Ребята, я обнаружил, что JQuery имеет только один эффект: страница перезагружается при нажатии кнопки назад. Это не имеет ничего общего с « готов ».

Как это работает? Ну, JQuery добавляет прослушиватель событий onunload .

// http://code.jquery.com/jquery-latest.js
jQuery(window).bind("unload", function() { // ...

По умолчанию это ничего не делает. Но почему-то это вызывает перезагрузку в Safari, Opera и Mozilla - независимо от того, что содержит обработчик событий.

[ edit (Николай) : вот почему так работает: webkit.org , developer.mozilla.org . Пожалуйста, прочитайте эти статьи (или мое резюме в отдельном ответе ниже) и подумайте, действительно ли вам нужно это сделать и замедлить загрузку вашей страницы для пользователей.]

Не можете в это поверить? Попробуй это:

<body onunload=""><!-- This does the trick -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>

Вы увидите похожие результаты при использовании JQuery.

Вы можете сравнить с этим без onunload

<body><!-- Will not reload on back button -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>
user123444555621
источник
1
Очень хорошо ... хотя это недокументированная функция / ошибка, хотя и может просто перестать работать в будущих версиях браузера, но это все еще интересно.
Вадих М.
3
Это также работает (не забудьте про часть onunload = "", иначе не будет работать на ff3): <body onload = "alert ('onload');" onunload = "">
Вади М.
3
Это связано с тем, что браузер предполагает, что страница не кэшируется, если у нее есть onunloadобработчик (страница уже все уничтожила; зачем ее кэшировать?).
Кейси Чу
14
Кажется, что ответ не работает в современных браузерах - проверено в последних версиях Chrome и Opera
Эндрю
10
это не работает в iPad Safari ... пожалуйста, снимите отметку как ответ
xus
74

Некоторые современные браузеры (Firefox, Safari и Opera, но не Chrome) поддерживают специальный кэш «назад / вперед» (я назову его bfcache - термин, изобретенный Mozilla), используемый при переходе пользователя назад. В отличие от обычного (HTTP) кэша, он фиксирует полное состояние страницы (включая состояние JS, DOM). Это позволяет перезагружать страницу быстрее и в точности так, как ее покинул пользователь.

loadСобытие не должно огня , когда страница загружается из этого bfcache. Например, если вы создали свой пользовательский интерфейс в обработчике «load», и событие «load» было запущено один раз при начальной загрузке и во второй раз, когда страница была перезагружена из bfcache, страница в итоге получит дубликаты элементов интерфейса.

По этой же причине добавление обработчика «unload» останавливает сохранение страницы в bfcache (что замедляет переход к ней) - обработчик unload может выполнять задачи очистки, которые могут привести страницу в нерабочее состояние.

Для страниц, которые должны знать, когда они перемещаются назад или обратно, Firefox 1.5+ и версия Safari с исправлением для ошибки 28758 поддерживают специальные события, называемые «pageshow» и «pagehide».

Ссылки:

Nickolay
источник
Это очень круто. Сейчас я нахожусь в ситуации, когда мои манипуляции с dom не сохраняются в bfcache. Есть ли ситуации, когда вы могли бы ожидать этого?
Бенсон
1
@Benson: возможные причины, по которым Firefox не будет сохранять вашу страницу в bfcache, перечислены на странице dev.mo, на которую я ссылался. Я не думаю, что возможно сохранить страницу в bfcache, но определенное состояние DOM не будет сохранено.
Николай
Николай, я получаю ваше нежелание принудительно перезагружать и отменять хорошую работу, проделанную bfcache, но есть ли другой способ обновить dom страницы в bfcache? Например, рассмотрим ситуацию, когда я перехожу со страницы, содержащей список сообщений, к одному из них, и когда я возвращаюсь назад, я хочу, чтобы индикатор чтения / непрочитанного изменился. Как это можно сделать без перезагрузки страницы?
Грег
@Greg: вы имеете в виду разработчика, управляющего страницей? Запустите AJAX-запрос от слушателя страниц.
Николай
Любые идеи о том, как использовать jQuery и получить быструю поддержку bfcache?
Алекс Блэк
31

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

После некоторого тестирования я обнаружил, что readyState элемента на странице, где был нажат назад, не «загружен», а «завершен». Добавление|| element.readyState == 'complete' к моему условному заявлению решило мои проблемы.

Просто подумал, что поделюсь своими выводами, надеюсь, они помогут кому-то еще.

Изменить для полноты

Мой код выглядел следующим образом:

script.onreadystatechange(function(){ 
   if(script.readyState == 'loaded' || script.readyState == 'complete') {
      // call code to execute here.
   } 
});

В приведенном выше примере кода переменной сценария был недавно созданный элемент сценария, который был добавлен в DOM.

Брайан Хиз
источник
7
Где ты это добавил? И как вы получили что-нибудь, чтобы выстрелить после того, как пользователь отвечает? Пожалуйста, покажите нам код!
Кериган
Что вы имеете в виду, когда говорите «мое условное утверждение»?
Филипп Сенн
1
@Phillip Условный оператор - это оператор if.
Брайан Хиз
22

Хорошо, вот окончательное решение, основанное на первоначальном решении ckramer и примере palehorse, которое работает во всех браузерах, включая Opera. Если вы установили history.navigationMode в «совместимый», тогда функция готовности jQuery будет срабатывать при операциях с кнопками «Назад» в Opera, а также в других основных браузерах.

Эта страница имеет больше информации .

Пример:

history.navigationMode = 'compatible';
$(document).ready(function(){
  alert('test');
});

Я проверил это в Opera 9.5, IE7, FF3 и Safari, и это работает во всех из них.

Билл
источник
2
Очевидно, это было какое-то время (около 5,5 лет), но стоит отметить, что ваша ссылка не работает.
Джефф
2
Это решение не работает для меня. У меня есть эта проблема в последнем Firefox (45.0.1)
Armin
6

Я не мог заставить приведенные выше примеры работать. Я просто хотел вызвать обновление определенных измененных областей div при возврате на страницу с помощью кнопки назад. Уловка, которую я использовал, состояла в том, чтобы установить скрытое поле ввода (называемое «грязным битом») в 1, как только области div изменились от оригинала. Скрытое поле ввода на самом деле сохраняет свое значение, когда я нажимаю назад, поэтому при загрузке я могу проверить этот бит. Если он установлен, я обновляю страницу (или просто обновляю div). Однако при первоначальной загрузке этот бит не установлен, поэтому я не трачу время на загрузку страницы дважды.

<input type='hidden' id='dirty'>

<script>
$(document).ready(function() {
  if ($('#dirty').val()) {
    // ... reload the page or specific divs only
  }
  // when something modifies a div that needs to be refreshed, set dirty=1
  $('#dirty').val('1');
});
</script>

И он будет срабатывать правильно, когда я нажму кнопку «Назад».

thorie
источник
3
Хотя это не работает в Firefox, я думаю, что это хитрый способ справиться с ситуацией в IE / Chrome, где сохранение скрытого поля очень полезно. Я использовал ваш трюк, а также событие «pagehow», поэтому я рассмотрю все основные браузеры.
Магнус Смит
Какой браузер не работает с pagehow, что это делает?
Джастин
4

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


источник
4

Я думал, что это будет для "onunload", а не для загрузки страницы, так как мы не говорим о запуске события при нажатии "Back"? $ document.ready () - для событий, желаемых при загрузке страницы, независимо от того, как вы попадаете на эту страницу (например, перенаправление, открытие браузера по URL-адресу напрямую и т. д.), а не при нажатии «Назад», если вы не говорите о том, что выстрелить на предыдущей странице, когда он загружается снова. И я не уверен, что страница не кэшируется, так как я обнаружил, что Javascripts все еще есть, даже если в них включен $ document.ready (). Нам приходилось нажимать Ctrl + F5 при редактировании наших сценариев, которые имеют это событие, всякий раз, когда мы их пересматриваем, и мы хотим проверить результаты на наших страницах.

$(window).unload(function(){ alert('do unload stuff here'); }); 

это то, что вы хотели бы для события onunload при нажатии «Назад» и выгрузке текущей страницы, а также срабатывает, когда пользователь закрывает окно браузера. Это больше походило на то, что вы хотели, даже если меня превосходят ответы $ document.ready (). По сути, разница между событием, запускаемым на текущей странице во время ее закрытия, и тем, которое загружается при нажатии кнопки «Назад» во время загрузки. Протестировано в IE 7 хорошо, не могу говорить за другие браузеры, поскольку они не допускаются, где мы находимся. Но это может быть другой вариант.

Том
источник
4

Я могу подтвердить ckramer, что готовое событие jQuery работает в IE и FireFox. Вот пример:

<html>
<head>
    <title>Test Page</title>
    <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
    <script type="text/javascript">
            $(document).ready(function () {
               var d = new Date();
               $('#test').html( "Hi at " + d.toString() );
            });
    </script>
</head>
<body>
    <div id="test"></div>
    <div>
        <a href="http://www.google.com">Go!</a>
    </div>
</body>
</html>
бледная лошадь
источник
4

для людей, которые не хотят использовать всю библиотеку jquery, я извлек реализацию в отдельный код. Это всего 0,4 КБ.

Вы можете найти код вместе с учебником немецкого языка в этой вики: http://www.easy-coding.de/wiki/html-ajax-und-co/onload-event-cross-browser-kompatibler-domcontentloaded.html

Торбен Бродт
источник
1
Одинокая ссылка считается плохим ответом (см. Часто задаваемые вопросы ), поскольку она сама по себе бессмысленна, и целевой ресурс не гарантированно будет жив в будущем . Было бы предпочтительным включить сюда основные части ответа и предоставить ссылку для справки.
J0K
3

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

ckramer
источник
6
Спустя долгое время, readyпохоже, не запускается в Firefox при использовании кнопки «Назад». Смотрите также ответ Николая .
Арджан
2

Билл, я смею ответить на твой вопрос, однако я не уверен на 100% в своих догадках. Я думаю, что другие браузеры IE при переносе пользователя на страницу в истории не только загрузят страницу и ее ресурсы из кэша, но и восстановят для нее все состояние DOM (чтение сеанса). IE не выполняет восстановление DOM (или не сдавал в аренду), и, таким образом, событие onload кажется необходимым для правильной повторной инициализации страницы.

Сергей Ильинский
источник
2

Я попробовал решение от Билла, используя $ (document) .ready ... но сначала это не сработало. Я обнаружил, что если сценарий размещен после раздела html, он не будет работать. Если это головной раздел, он будет работать, но только в IE. Скрипт не работает в Firefox.

Johann
источник
1

Хорошо, я попробовал это, и это работает в Firefox 3, Safari 3.1.1 и IE7, но не в Opera 9.52.
Если вы используете пример, показанный ниже (на основе примера palehorse), вы получите всплывающее окно с предупреждением при первой загрузке страницы. Но если вы затем перейдете на другой URL, а затем нажмете кнопку «Назад», чтобы вернуться на эту страницу, вы не получите всплывающее окно с предупреждением в Opera (но вы делаете это в других браузерах).

Во всяком случае, я думаю, что это достаточно близко на данный момент. Спасибо всем!

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<meta http-equiv="expires" content="0">
<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready( 
                    function(){
                      alert('test');
                    }
                 );
</script>
</head>
<body>
<h1>Test of the page load event and the Back button using jQuery</h1>
</body>
</html>
Билл
источник
1

Событие unload не работает нормально в IE 9. Я пробовал его с событием load (onload ()), оно отлично работает в IE 9 и FF5 .

Пример:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
    jQuery(window).bind("load", function() {
        $("[name=customerName]").val('');
    });
</script>
</head>
<body>
    <h1>body.jsp</h1>
    <form action="success.jsp">
        <div id="myDiv">

        Your Full Name: <input name="yourName" id="fullName"
            value="Your Full Name" /><br> <br> <input type="submit"><br>

        </div>

    </form>
</body>
</html>
mallesham
источник
0

Я использовал HTML-шаблон. В файле custom.js этого шаблона была такая функция:

    jQuery(document).ready(function($) {

       $(window).on('load', function() {
          //...
       });

    });

Но эта функция не работала, когда я возвращался после перехода на другую страницу.

Итак, я попробовал это, и это сработало:

    jQuery(document).ready(function($) {
       //...
    });

   //Window Load Start
   window.addEventListener('load', function() {
       jQuery(document).ready(function($) {
          //...
       });
   });

Теперь у меня есть 2 «готовых» функции, но они не дают никаких ошибок, и страница работает очень хорошо.

Тем не менее, я должен заявить, что он тестировал на Windows 10 - Opera v53 и Edge v42, но не на других браузерах. Имейте в виду это ...

Примечание: версия jquery была 3.3.1, а версия перехода была 3.0.0

bafsar
источник