Чи існує подія завантаження між браузером при натисканні кнопки "Назад"?


185

Для всіх основних браузерів (крім IE) onloadподія JavaScript не спрацьовує, коли сторінка завантажується в результаті роботи кнопки "назад" - вона запускається лише під час першого завантаження сторінки.

Чи може хтось вказати мені на якийсь зразок крос-браузерного коду (Firefox, Opera, Safari, IE,…), який вирішує цю проблему? Я знайомий з pageshowподією Firefox, але, на жаль, ні Opera, ні Safari цього не виконують.


6
Це не проблема - вона дозволяє швидко завантажувати веб-сторінку, коли користувач натискає кнопку Назад. Детальну інформацію див. У моїй відповіді нижче. Пропоновані тут шляхи вирішення проблеми роблять веб-сторінку більш дратівливою для користувача, оскільки переміщення назад / вперед відбувається повільніше.
Миколай

2
@romkyns: ваш коментар не пов'язаний з цим питанням. Коли браузери не відновлюють стан JS / DOM, вони запускають події завантаження.
Миколай

IOS 5 + кнопка Історія назад вирішена тут stackoverflow.com/a/12652160/1090395
Младен Janjetovic

Відповіді:


117

Хлопці, я виявив, що JQuery має лише один ефект: сторінка перезавантажується при натисканні кнопки "Назад". Це не має нічого спільного з " готовими ".

Як це працює? Ну, JQuery додає OnUnload слухача подій.

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

За замовчуванням він нічого не робить. Але якось це, здається, викликає перезавантаження в Safari, Opera та Mozilla - незалежно від того, що містить обробник подій.

[ редагувати (Ніколай) : ось чому це працює так: 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>

1
Дуже приємно .. хоча це недокументована функція / помилка, хоч і може просто перестати працювати в майбутніх версіях браузера, але це все ще цікаво.
Wadih M.

3
Це також працює (не забудьте частину onunload = "", інакше не буде працювати на ff3): <body onload = "alert ('onload');" onunload = "">
Wadih M.

3
Це тому, що браузер припускає, що сторінка не підлягає кеш-пам'яті, якщо вона має onunloadобробник (сторінка вже знищила все; чому її кешувати?).
Кейсі Чу

14
Відповідь, здається, не працює в сучасних браузерах - перевірено в останніх Chrome і Opera
Ендрю

10
це не працює в iPad safari ... будь ласка, відмітьте це як відповідь
xus

74

Деякі сучасні браузери (Firefox, Safari і Opera, але не Chrome) підтримують спеціальний кеш "назад / вперед" (я називаю це bfcache, що є терміном, винайденим Mozilla), який бере участь у користуванні, коли користувач переходить назад. На відміну від звичайного кешу (HTTP), він фіксує повний стан сторінки (включаючи стан JS, DOM). Це дозволяє йому швидше завантажувати сторінку та точно так, як її залишив користувач.

loadПодія не повинно вогню , коли сторінка завантажується з цього bfcache. Наприклад, якщо ви створили свій інтерфейс користувача в обробнику "load", і подія "load" була запущена один раз під час початкового завантаження, а вдруге, коли сторінку було повторно завантажено з bfcache, сторінка закінчиться копії елементів інтерфейсу.

Це також, чому додавання обробника "вивантажувати" перешкоджає збереженню сторінки в bfcache (таким чином, це повільніше повертається назад до) - обробник завантаження може виконувати завдання очищення, що може залишити сторінку в непрацездатному стані.

Для сторінок, які повинні знати, коли вони переходять / повертаються назад, Firefox 1.5+ та версія Safari з виправленням помилки 28758 підтримують спеціальні події, що називаються "pagehow" та "pagehide".

Список літератури:


Це дуже круто. На даний момент я переживаю ситуацію, коли мої маніпуляції з домом не зберігаються в bfcache. Чи є ситуації, коли ви цього можете очікувати?
Бенсон

1
@Benson: можливі причини, коли Firefox не збереже вашу сторінку в bfcache, перераховані на сторінці dev.mo, до якої я пов’язаний. Я не думаю, що неможливо зберегти сторінку в bfcache, але певний стан DOM не можна зберегти.
Миколай

Ніколай, я відчуваю ваше небажання змушувати перезавантажувати та скасовувати добру роботу, виконану bfcache, але чи є інший спосіб оновити купон сторінки у bfcache? Наприклад, розгляньте ситуацію, коли я переходжу зі сторінки, на якій є список повідомлень до одного з них, і коли я повертаюсь "назад", я хочу, щоб індикатор читання / непрочитані змінився. Як це можна зробити, не завантажуючи сторінку?
Грег

@Greg: ти маєш на увазі розробника, який контролює сторінку? Відключіть запит ajax від слухача "showhow".
Миколай

Будь-які ідеї, як використовувати 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, як тільки ділові ділянки змінилися з оригінальних. Приховане поле введення фактично зберігає своє значення при натисканні назад, тому при завантаженні я можу перевірити цей біт. Якщо встановлено, я оновлю сторінку (або просто оновлю діви). Однак для початкового завантаження біт не встановлений, тому я не витрачаю час на завантаження сторінки двічі.

<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>

І спрацьовуватиме належним чином кожного разу, коли я натискаю кнопку назад.


3
Хоча це не працює у Firefox, я думаю, що це хитрий спосіб вирішити ситуацію в IE / Chrome, де збереження прихованого поля дуже корисне. Я використав ваш трюк, а також подію "showhow", тому я висвітлюю всі основні браузери.
Магнус Сміт

Який браузер не працює зі сторінками, що це робить?
Джастін

4

Якщо я пам'ятаю правильно, то додавання події unload () означає, що цю сторінку не можна кешувати (в кеш вперед / назад) - тому що це зміни станів / можуть змінитися, коли користувач переходить геть. Отже - відновити стан останньої другої сторінки при поверненні до неї не безпечно, переходячи по об’єкту історії.


4

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

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

це те, що ви хотіли б для події завантаження, натискаючи "Назад" та вивантажуючи поточну сторінку, а також запускатиметься, коли користувач закриває вікно браузера. Це звучало більше як те, що було бажано, навіть якщо я перерахував відповіді $ 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
Одиноке посилання вважається поганою відповіддю (див. Faq ), оскільки воно само по собі безглуздо і цільовий ресурс не гарантовано буде живим у майбутньому . Тут було б краще включити істотні частини відповіді та надати посилання для довідки.
j0k

3

Готова подія jQuery створена саме для такого виду. Можливо, ви захочете заглибитись у реалізацію, щоб побачити, що відбувається під кришками.


6
Тривалий час, readyздається, не запускається у Firefox, коли використовується кнопка Назад. Дивіться також відповідь Ніколая .
Ар'ян

2

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


2

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


1

Гаразд, я спробував це, і він працює в Firefox 3, Safari 3.1.1 та IE7, але не в Opera 9.52.
Якщо ви використовуєте приклад, показаний нижче (на основі прикладу палецького коня), ви отримуєте спливаюче вікно сповіщення, коли сторінка спочатку завантажується. Але якщо ви перейдете до іншої 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

Подія вивантаження не працює добре на IE 9. Я спробував це з подіями завантаження (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>

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.