Як визначити, чи користувач потрапив на сторінку за допомогою кнопки "Назад"?


90

Це питання схоже на Track, коли користувач натискає кнопку назад у веб-переглядачі , але не те саме ... У мене є рішення, і я публікую його тут для довідки та зворотного зв'язку. Якщо хтось має якісь кращі варіанти, я всі вуха!

Ситуація така, що у мене є сторінка з "редагуванням на місці", a la flickr. Тобто є "натисніть тут, щоб додати опис" DIV, який при натисканні перетворюється в ТЕКСТАРЕ з кнопками Зберегти та Скасувати. Натискання кнопки Зберегти публікує дані на сервері, щоб оновити базу даних, а новий опис розміщується в DIV замість TEXTAREA. Якщо сторінку оновлено, новий опис відображається з бази даних із опцією "натисніть для редагування". Сьогодні досить стандартний вміст веб 2.0.

Проблема в тому, що якщо:

  1. сторінка завантажується без опису
  2. користувач додає опис
  3. сторінка орієнтується, натиснувши посилання
  4. користувач натискає кнопку "Назад"

Тоді відображається (з кешу браузера) версія сторінки без динамічно модифікованого DIV, що містить новий опис.

Це досить велика проблема, оскільки користувач припускає, що його оновлення втрачено, і не обов'язково розуміє, що йому потрібно оновити сторінку, щоб побачити зміни.

Отже, питання полягає в тому: Як ви можете позначити сторінку як модифіковану після її завантаження, а потім визначити, коли користувач "повернеться до неї", і примусити оновити у цій ситуації?


Чим це відрізняється від питання, яке ви цитували?
innaM

питання схоже, але я думаю, що оточення і, отже, відповідь інша, я можу помилитися. моє тлумачення того, яка проблема може бути вирішена за допомогою іншого рішення, полягає в тому, що користувач натискає вкладку на сторінці, яку завантажує ajax, потім іншу вкладку тощо. натискання кнопки "Назад" призведе до повернення на іншу сторінку, а не на попередню вкладку. вони хочуть повернутися до "історії ajax" у межах "історії сторінок". принаймні, таке моє враження від того, що повинен робити Yahoo Browser History Manager. я хотів чогось трохи більш базового.
Том

Прийнята відповідь містить трюк iframe.
innaM

Відповіді:


79

Використовуйте приховану форму. Дані форми зберігаються (як правило) у веб-переглядачах, коли ви перезавантажуєте або натискаєте кнопку "Назад", щоб повернутися на сторінку. На вашій сторінці розміщено наступне (можливо, внизу):

<form name="ignore_me">
    <input type="hidden" id="page_is_dirty" name="page_is_dirty" value="0" />
</form>

У вашому javascript вам знадобиться таке:

var dirty_bit = document.getElementById('page_is_dirty');
if (dirty_bit.value == '1') window.location.reload();
function mark_page_dirty() {
    dirty_bit.value = '1';
}

Js, який нюхає форму, повинен виконуватися після повного аналізу html, але ви можете розмістити форму та js вбудованими у верхній частині сторінки (js секунду), якщо затримка користувача викликає серйозне занепокоєння.


5
"Дані форми зберігаються (як правило) у браузерах" - чи можете ви розширити їх? це не збереглося в деяких браузерах? чи в деяких ситуаціях?
Том,

4
Насправді, дозвольте мені перерахувати всі способи, якими я можу думати про це, щоб піти не так. (1) Opera зберігає повний стан сторінки та не виконує js повторно. (2) Якщо ваші налаштування кешу налаштовані, щоб змусити сторінку завантажуватися із сервера за допомогою кнопки «Назад», дані форми можуть загубитися, що чудово для цілей цього запитання. (3) Телефонні браузери мають набагато менший кеш, і браузер, можливо, вже видалив сторінку з кешу (для цих цілей це не проблема).
Нік Уайт

10
У деяких браузерах приховані теги не зберігаються. Таким чином, ви можете використовувати прихований текстовий тег замість того, щоб використовувати прихований тег введення. <input type = "text" value = "0" id = 'txt' name = 'txt' style = "display: none" />
sajith

2
Для мене це чудово працювало. Я впевнений, що у нього трапляються ситуації, коли він виходить з ладу, але кожне рішення цієї проблеми буде.
Йорен

Це не працює на iPhone з браузером Safari, спробуйте, коли ви натискаєте кнопку назад, js не викликається знову.
woheras

52

Ось дуже просте сучасне рішення цієї старої проблеми.

if (window.performance && window.performance.navigation.type === window.performance.navigation.TYPE_BACK_FORWARD) {
    alert('Got here using the browser "Back" or "Forward" button.');
}

window.performance в даний час підтримується усіма основними браузерами.


Я не чув про це. Я щойно знайшов цю документацію ( developer.mozilla.org/en-US/docs/Web/API/Performance/navigation ) і хотів би почути вашу деталізацію (наприклад, чому потрібна window.performance && window.performance.navigation.typeзамість просто window.performance.navigation.TYPE_BACK_FORWARD?).
Райан

5
window.performance.navigation.TYPE_BACK_FORWARDце константа, яка завжди дорівнює 2. Отже, вона просто використовується для порівняння.
Басем

Performance.navigation підтримується на всіх пристроях, крім andorid & opera mini, але жодних проблем не дуже добре ( developer.mozilla.org/en-US/docs/Web/API/Performance/navigation )
Ельбаз,

1
Схоже performance.navigation, застарілий і пропонується замість нього використовувати developer.mozilla.org/en-US/docs/Web/API/…
RubberDuckRabbit

1
Firefox v70 підтримуватиме performance.navigation = 2для натискань кнопки "Назад". До v70 він неправильно повернувся 1.
Енді Мерсер

13

Ця стаття пояснює це. Дивіться код нижче: http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/

<html>
    <head>
        <script>

            function pageShown(evt){
                if (evt.persisted) {
                    alert("pageshow event handler called.  The page was just restored from the Page Cache (eg. From the Back button.");
                } else {
                    alert("pageshow event handler called for the initial load.  This is the same as the load event.");
                }
            }

            function pageHidden(evt){
                if (evt.persisted) {
                    alert("pagehide event handler called.  The page was suspended and placed into the Page Cache.");
                } else {
                    alert("pagehide event handler called for page destruction.  This is the same as the unload event.");
                }
            }

            window.addEventListener("pageshow", pageShown, false);
            window.addEventListener("pagehide", pageHidden, false);

        </script>
    </head>
    <body>
        <a href="http://www.webkit.org/">Click for WebKit</a>
    </body>
</html>

1
Це хороша відповідь, працює в останній версії Chrome 40 / Firefox 35. Однак IE11 не підтримує ці події.
Слава Абакумов

За даними caniuse.com/#feat=page-transition-events події переходу сторінки насправді підтримуються в IE11 +. Як ми вже говоримо, глобальне охоплення цієї функції на 88%
Крістіан

FYI, Chrome повертає event.persisted= false, навіть при натисканні кнопки назад. Ви повинні використовувати window.performance.navigationабо PerformanceNavigationTiming для Chrome.
Енді Мерсер

4

Для сучасних браузерів це, здається, зараз правильний шлях:

const perfEntries = performance.getEntriesByType('navigation');
if (perfEntries.length && perfEntries[0].type === 'back_forward') {
  console.log('User got here from Back or Forward button.');
}

Станом на січень 2020 р. Це все ще "Експериментально", але, схоже, підтримується добре.

https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming


1
краще використовувати === замість ==
Aboozar Rajabi

2

Як уже згадувалося вище, я знайшов рішення і публікую його тут для довідки та зворотного зв’язку.

Першим етапом рішення є додавання на сторінку наступного:

<!-- at the top of the content page -->
<IFRAME id="page_is_fresh" src="fresh.html" style="display:none;"></IFRAME>
<SCRIPT style="text/javascript">
  function reload_stale_page() { location.reload(); }
</SCRIPT>

Вміст fresh.htmlне є важливим, тому достатньо наступного:

<!-- fresh.html -->
<HTML><BODY></BODY></HTML>

Коли клієнтський код оновлює сторінку, йому потрібно позначити модифікацію наступним чином:

function trigger_reload_if_user_clicks_back_button()
{
  // "dis-arm" the reload stale page function so it doesn't fire  
  // until the page is reloaded from the browser's cache
  window.reload_stale_page = function(){};

  // change the IFRAME to point to a page that will reload the 
  // page when it loads
  document.getElementById("page_is_fresh").src = "stale.html";
}

stale.htmlробить всю роботу: Коли він буде завантажений, він викличе reload_stale_pageфункцію, яка при необхідності оновить сторінку. Під час першого завантаження (тобто після внесення змін reload_stale_pageфункція нічого не зробить.)

<!-- stale.html -->
<HTML><BODY>
<SCRIPT type="text/javascript">window.parent.reload_stale_page();</SCRIPT>
</BODY></HTML>

З мого (мінімального) тестування на цьому етапі, здається, це працює за бажанням. Я щось пропустив?


Не те, що я знаю, але я не перевірив його повністю. getElementById не підтримується в деяких старих браузерах, але його легко замінити на jquery або щось інше, якщо потрібно.
Том

2

Ви можете вирішити це за допомогою події onbeforeunload :

window.onbeforeunload = function () { }

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

Ось повний код прикладу:

<html>
<head>
<title>onbeforeunload.html</title>
<script>
window.onbeforeunload = function () { }

function myfun()
{
   alert("The page has been refreshed.");
}
</script>

<body onload="myfun()">

Hello World!<br>

</body>
</html>

Спробуйте, відвідайте цю сторінку, а потім поверніться назад, використовуючи кнопки "Назад" або "Вперед" у вашому браузері.

Він чудово працює в IE, FF та Chrome.

Звичайно, ви можете робити все, що завгодно, у функції myfun .

Докладніше: http://www.hunlock.com/blogs/Mastering_The_Back_Button_With_Javascript


Працює в Safari для мене
Якоб

2

Ви можете використовувати localStorage або sessionStorage ( http://www.w3schools.com/html/html5_webstorage.asp ), щоб встановити прапор (замість використання прихованої форми).


його приємний обхідний шлях, але як ти це робиш, якщо він хоче виявити це кожен раз, коли я відкривав сайт і закривав його, мені потрібно виявляти, коли я відкривав, і повертатися назад перед закриттям
Ельбаз,

1

Використовуючи цю сторінку, особливо включаючи коментар @sajith щодо відповіді @Nick White та цієї сторінки: http://www.mrc-productivity.com/techblog/?p=1235

<form name="ignore_me" style="display:none">
    <input type="text" id="reloadValue" name="reloadValue" value="" />
</form>

$(function ()
{
    var date = new Date();
    var time = date.getTime();

    if ($("#reloadValue").val().length === 0)
    {
        $("#reloadValue").val(time);
    }
    else
    {
        $("#reloadValue").val("");
        window.location.reload();
    }
});

1

Ось версія jQuery. Мені довелося кілька разів використовувати його через те, як Safari настільний / мобільний обробляє кеш, коли користувач натискає кнопку "Назад".

$(window).bind("pageshow", function(event) {
    if (event.originalEvent.persisted) {
        // Loading from cache
    }
});

Здається, це не працює в Chrome, наскільки я можу зрозуміти. Console.log запускається лише в операторі else (додається для тестування) незалежно від того, як я отримую доступ до сторінки.
Лука

0

Сьогодні я зіткнувся з подібною проблемою і вирішив її за допомогою localStorage (тут з трохи jQuery):

$(function() {

    if ($('#page1').length) {
        // this code must only run on page 1

        var checkSteps = function () {
            if (localStorage.getItem('steps') == 'step2') {
                // if we are here, we know that:
                // 1. the user is on page 1
                // 2. he has been on page 2
                // 3. this function is running, which means the user has submitted the form
                // 4. but steps == step2, which is impossible if the user has *just* submitted the form
                // therefore we know that he has come back, probably using the back button of his browser
                alert('oh hey, welcome back!');
            } else {
                setTimeout(checkSteps, 100);
            }
        };

        $('#form').on('submit', function (e) {
            e.preventDefault();
            localStorage.setItem('steps', 'step1'); // if "step1", then we know the user has submitted the form
            checkOrderSteps();
            // ... then do what you need to submit the form and load page 2
        });
    }

    if ($('#page2').length) {
        // this code must only run on page 2
        localStorage.setItem('steps', 'step2');
    }

});

Si в основному:

На сторінці 1, коли користувач подає форму, ми встановлюємо значення "кроки" в localStorage, щоб вказати, який крок користувач зробив. Одночасно ми запускаємо функцію з тайм-аутом, яка перевіряє, чи не було змінено це значення (наприклад, 10 разів на секунду).

На сторінці 2 ми негайно змінюємо вказане значення.

Отже, якщо користувач використовує кнопку «Назад» і браузер відновлює сторінку 1 у тому самому стані, який був коли ми її залишили, функція checkSteps все ще працює, і вона може виявити, що значення в localStorage було змінено (і може вжити відповідних заходів ). Як тільки ця перевірка виконає свою мету, немає необхідності продовжувати її виконувати, тому ми просто більше не використовуємо setTimeout.

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