Как заставить Firefox запускать событие popstate при возврате со страницы в другом домене?

У меня есть простая веб-страница, а именно:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>History hacks</title>
<script>
window.onpopstate = function (e) {
    alert("location: " + document.location + ", state: " + JSON.stringify(e.state));
}
window.onload = function (e) {
    alert('page loaded');
}
</script>
</head>
<body>
<p> <a href="http://www.yahoo.com">Yahoo</a> <a href="#part1">Part 1</a></p>
</body>
</html>

Теперь есть ряд различий относительно того, как Chrome и Firefox вызывают событие popstate (мне страшно подумать, с чем я столкнулся, когда приступаю к тестированию IE), но одно, что вызывает у меня проблемы, заключается в том, что Chrome будет запускать popstate. событие, когда я нажимаю на любую из этих двух ссылок, а затем снова, когда я нажимаю кнопку "Назад". Firefox вызовет событие для ссылки, которая изменяет хеш-часть (только в первый раз, хотя хеш-ссылка такая же), и не будет запускать ее вообще, если я нажму на ссылку Yahoo, а затем нажму кнопку "Назад".

Так есть ли способ, которым я могу сказать в Firefox, что пользователь только что нажал назад и вернулся на мою страницу с совершенно другого сайта в другом домене? Есть ли другое событие, которое будет работать для этой цели в Firefox? (Событие загрузки также не запускается, когда я возвращаюсь с yahoo.com.)

4 ответа

Чтобы получить popstate событие, когда кнопка "назад" (или "вперед") используется для перехода к начальной загрузке страницы, используйте replaceState() лайк

window.onload = function(e) {
  history.replaceState(null, null, document.URL);
}

Игнорировать начальный popstate что Chrome генерирует при загрузке страницы, вы можете пометить состояние при каждом вызове pushState / replaceState например,

history.pushState({myTag: true}, null, url);

Тогда ваш popstate обработчик просто фильтрует myTag

window.onpopstate = function(e) { 
  if (!e.state.myTag) return; // none of my business
  // code to handle popstate 
}

Вы можете объединить эти два для тривиального кросс-браузерного решения:

window.onpopstate = function(e) { 
  if (!e.state.myTag) return; // none of my business
  // code to handle popstate 
}

window.onload = function(e) {
  history.replaceState({myTag: true}, null, document.URL);
}

@Boris Zbarsky подробно описал bfcache. Я не думал о том, как совместить это с моим подходом. Я просто отключаю его, добавив страницу unload обработчик

window.onunload = function(e) { }

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

Обратите внимание, что если событие загрузки отсутствует, это также означает, что страница все еще имеет ту же среду выполнения DOM и скрипта, что и при удалении. По сути, это как если бы пользователь переключал вкладки на некоторое время, в отличие от навигации.

Итак, учитывая это, вы все еще хотите получить событие в этой ситуации? Получаете ли вы события, которые вы ищете, когда пользователь переключается обратно на вкладку с вашей страницей в нем?

Перед выгрузкой я перезагружаю свою страницу (чтобы получить начальный статус), затем устанавливаю новый href

window.onunload = function(e) {
  location.reload();
  location.href = **new_url** ;
}

Я должен сделать это, потому что Firefox сохраняет последнее состояние моей страницы и восстанавливает его, а не создает заново.

У меня был тот же вопрос, и мне пришлось изучить спецификацию, чтобы выяснить, почему событие popstate не запускается ни в одном браузере, когда кнопка "Назад" используется для возврата со страницы в другом домене. Оказывается, что в этом случае popstate не должен запускаться, поскольку измененное состояние документа не соответствует действительности, и popstate должно запускаться только в том случае, если измененное состояние имеет значение true. Для состояния, измененного, чтобы быть установленным в true, спецификация говорит:

Пусть состояние изменено будет истинным, если Документ указанной записи имеет последнюю запись, и эта запись не является указанной записью; в противном случае пусть это будет ложным.

Насколько я понимаю, когда мы возвращаемся на нашу страницу со страницы в другом домене, на нашей странице нет последней записи, поскольку документ изменился, а в новом документе еще нет последней записи. Опять из спецификации:

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

Однако все еще есть способ узнать, вернулся ли пользователь на вашу страницу, установив флаг в history.state на своей странице, используя методы pushState или replaceState, и проверив наличие этого флага в history.state при загрузке страницы.

Подробнее читайте в HTML-спецификации WHATWG о части события popstate: https://html.spec.whatwg.org/multipage/browsers.html

Другие вопросы по тегам