Как определить, попал ли пользователь на страницу с помощью кнопки "Назад"?

Этот вопрос похож на Отслеживать, когда пользователь нажимает кнопку в браузере, но не тот же... У меня есть решение, и я размещаю его здесь для справки и обратной связи. Если у кого-то есть лучшие варианты, я все уши!

Ситуация заключается в том, что у меня есть страница с "редактированием на месте", a la flickr. То есть есть "нажмите здесь, чтобы добавить описание" DIV, который при щелчке превращается в TEXTAREA с кнопками "Сохранить" и "Отмена". Нажатие "Сохранить" сохраняет данные на сервере для обновления базы данных и помещает новое описание в DIV вместо TEXTAREA. Если страница обновлена, новое описание отображается в базе данных с опцией "click to edit". Достойно стандартный веб 2.0 в наши дни.

Проблема в том, что если:

  • страница загружается без описания
  • описание добавляется пользователем
  • страница переместится, нажав ссылку
  • пользователь нажимает кнопку "Назад"

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

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

Итак, возникает вопрос: как вы можете пометить страницу как измененную после ее загрузки, а затем определить, когда пользователь "вернется к ней" и принудительно обновить в этой ситуации?

Ответ 1

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

<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 second), если пользовательская латентность вызывает серьезную озабоченность.

Ответ 2

В этой статье объясняется это. См. Следующий код: 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>

Ответ 3

Вот очень простое современное решение этой старой проблемы.

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 в настоящее время поддерживается всеми основными браузерами.

Ответ 4

Как упоминалось выше, я нашел решение и размещаю его здесь для справки и обратной связи.

Первый этап решения - добавить на страницу следующее:

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

Из моего (минимального) тестирования на этом этапе это, похоже, работает по своему желанию. Я что-то пропустил?

Ответ 5

Вы можете использовать localStorage или sessionStorage (http://www.w3schools.com/html/html5_webstorage.asp), чтобы установить флаг (вместо использования скрытой формы).

Ответ 6

Вы можете решить эту проблему, используя событие onbeforeunload:

window.onbeforeunload = function () { }

Ответ 7

Используя эту страницу, особенно учитывая комментарий @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();
    }
});

Ответ 8

Сегодня я столкнулся с подобной проблемой, и я решил ее с помощью 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.

Ответ 9

Здесь версия jQuery. Мне пришлось использовать его несколько раз из-за того, как рабочий стол/мобильный телефон Safari обрабатывает кеш, когда пользователь нажимает кнопку "Назад".

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