Как проверить, может ли пользователь вернуться в историю браузера или нет

151

Я хочу использовать JavaScript, чтобы увидеть, есть ли история или нет, я имею в виду, доступна ли кнопка назад в браузере или нет.

Райан
источник
1
Связанный stackoverflow.com/questions/19417084/…
Adrien Be

Ответы:

119

Краткий ответ: вы не можете.

Технически существует точный способ, которым будет проверяться свойство:

history.previous

Однако это не сработает. Проблема в том, что в большинстве браузеров это считается нарушением безопасности и обычно просто возвращает undefined .

history.length

Это свойство, которое предложили другие ...
Однако длина не работает полностью, потому что она не указывает, где в истории вы находитесь. Кроме того, он не всегда начинается с одного номера. Например, браузер, для которого не настроена целевая страница, начинается с 0, а другой браузер, использующий целевую страницу, - с 1.

альтернативный текст

Большую часть времени добавляется ссылка, которая вызывает:

history.back();

или

 history.go(-1);

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

McAden
источник
Это хорошая информация, но она не решает проблему. Было бы разработать некоторый код, который действительно работает в любом браузере. Возможно, код, который сначала проверяет браузер, который вы используете.
Сантьяго Бендавид
5
Я говорю, что нет однозначного ответа. Вы говорите о плюсах и минусах каждого подхода, но не о том, как получить сценарий, который проверяет, какой браузер вы используете, и условно выполнить тот или иной фрагмент кода.
Сантьяго Бендавид
Могу ли я узнать, что вы подразумеваете под «Проблема с этим в том, что в большинстве браузеров это считается нарушением безопасности» Другой пользователь в другой теме также указал, что возможность получить историю браузера клиента нарушает безопасность, но не объясняет это почему. Кто-нибудь может привести пример того, что представляют собой угрозы безопасности?
Кевин Чандра
Веб-сайт не должен знать историю пользователя, которая может включать косвенную личную информацию. Сайт может использовать отслеживание / файлы cookie, чтобы знать, что пользователь делает на самом сайте, но им нельзя, например, разрешать выяснить, в каком банке я пользуюсь, в какую школу ходят мои дети и т. Д. Поэтому браузеры не разрешат доступ к этому свойству
McAden
85

Есть еще один способ проверить - проверить реферер. На первой странице обычно будет пустой реферер ...

if (document.referrer == "") {
    window.close()
} else {
    history.back()
}
Рон Рейтер
источник
3
Реферер может быть скрыт по соображениям конфиденциальности.
Корнель
11
Реферер всегда пуст, когда страница загружена не по ссылке, а путем ввода URL-адреса в адресную строку или загрузки закладки. Такие страницы, безусловно, могут иметь историю, когда вкладка / окно браузера уже загружала другую страницу!
ygoe
1
Но применимо решение для навигации по многостраничному сайту
Дан
36
Не работает, если окно было открыто с target = "_ blank", чтобы вызвать новое окно. Кнопка «Назад» в браузере не будет работать, но будет документ.referrer
Mike_K
3
Это не будет работать, если вы переходите с защищенной (HTTPS) страницы на небезопасную страницу (HTTP), так как это лишит реферера.
Кевин Бордерс
55

Мой код позволяет браузеру вернуться на одну страницу назад, и в случае неудачи он загружает запасной URL. Он также обнаруживает изменения хэштегов.

Если кнопка «Назад» недоступна, резервный URL-адрес будет загружен через 500 мс, поэтому у браузера будет достаточно времени для загрузки предыдущей страницы. Загрузка резервной ссылки сразу после window.history.go(-1);этого заставит браузер использовать запасную ссылку, потому что сценарий js еще не остановлен.

function historyBackWFallback(fallbackUrl) {
    fallbackUrl = fallbackUrl || '/';
    var prevPage = window.location.href;

    window.history.go(-1);

    setTimeout(function(){ 
        if (window.location.href == prevPage) {
            window.location.href = fallbackUrl; 
        }
    }, 500);
}
redelschaap
источник
7
Я думаю, что это действительно гвоздь в центре вопроса, почему человек заботится и что на самом деле можно сделать с этим надежным и последовательным образом.
Крис Марисик
1
Это работало до тех пор, пока я не взял URL, где находится кнопка «Назад», и вставил его в новую вкладку в Chrome. Нажатие на кнопку возврата привело к отправке на пустую вкладку. :(
karlingen
3
Это поведение Chrome по умолчанию. Вы «посетили» страницу chrome://newtabи, таким образом, можете вернуться в историю.
redelschaap
Осторожнее с этим, потому что при медленном сетевом соединении вы будете регулярно использовать резервный URL.
Камек
14

Вот как я это сделал.

Я использовал событие beforeunload для установки логического значения. Затем я установил тайм-аут, чтобы посмотреть, сработал ли «beforeunload».

var $window = $(window),
    $trigger = $('.select_your_link'),
    fallback = 'your_fallback_url';
    hasHistory = false;

$window.on('beforeunload', function(){
    hasHistory = true;
});

$trigger.on('click', function(){

    window.history.go(-1);

    setTimeout(function(){
        if (!hasHistory){
            window.location.href = fallback;
        }
    }, 200);

    return false;
});

Кажется, работает в основных браузерах (до сих пор тестировал FF, Chrome, IE11).

Тони Фейстауэр
источник
1
Это, безусловно, лучший ответ на вопрос. Вы можете легко заменить window.location.href = fallbackна, window.close()и это тоже работает.
Витани
13

это, кажется, делает трюк:

function goBackOrClose() {  

    window.history.back();
    window.close(); 

    //or if you are not interested in closing the window, do something else here
    //e.g. 
    theBrowserCantGoBack();

}

Вызовите history.back (), а затем window.close (). Если браузер сможет вернуться в историю, он не сможет перейти к следующему утверждению. Если он не сможет вернуться, он закроет окно.

Тем не менее, обратите внимание, что если страница была достигнута путем ввода URL-адреса, то Firefox не позволит сценарию закрыть окно.

xtrahelp.com
источник
3
Я обнаружил, что это не работает, если я не использую setTimeout с задержкой в ​​несколько сотен миллисекунд или около того, прежде чем пытаться выполнить следующий оператор, в противном случае он будет работать в любом случае после запуска history.back ()
Кен Фелинг,
Я не испытал это лично, какой браузер это было?
xtrahelp.com
Я работал нормально с функцией setTimeout в ответе ниже. например: setTimeout (function () {window.close ()}, 400);
Гилкрис
2
window.close()Считается угрозой безопасности во многих современных браузерах. Некоторые просто не позволят тебе это сделать.
Руди Кершоу
Вы можете сделать что-нибудь после window.history.back (); window.close (); это просто пример
hariszaman
13

В моих проектах есть фрагмент:

function back(url) {
    if (history.length > 2) {
        // if history is not empty, go back:
        window.History.back();
    } else if (url) {
        // go to specified fallback url:
        window.History.replaceState(null, null, url);
    } else {
        // go home:
        window.History.replaceState(null, null, '/');
    }
}

К вашему сведению: я использую History.js для управления историей браузера.


Зачем сравнивать history.length с номером 2?

Потому что стартовая страница Chrome считается первым элементом в истории браузера.


Есть несколько возможностей history.lengthи поведения пользователя:

  • Пользователь открывает новую пустую вкладку в браузере, а затем запускает страницу. history.length = 2и мы хотим отключить back()в этом случае, потому что пользователь перейдет на пустую вкладку.
  • Пользователь открывает страницу в новой вкладке , щелкая ссылку где-то раньше. history.length = 1и снова мы хотим отключить back()метод.
  • И, наконец, пользователь попадает на текущую страницу после перезагрузки нескольких страниц . history.length > 2и теперь back()можно включить.

Примечание: я опускаю случай, когда пользователь попадает на текущую страницу после нажатия на ссылку с внешнего сайта без target="_blank".

Примечание 2: document.referrer пусто, когда вы открываете веб-сайт путем ввода его адреса, а также когда веб-сайт использует ajax для загрузки подстраниц, поэтому я прекратил проверку этого значения в первом случае.

gregmatys
источник
Этот подход отлично сработал для меня. Я на самом деле храню статические резервные обратные ссылки для своих страниц, которые я использую на резервных.
Грег Бласс
Но, если вы вернетесь назад, длина history.length не изменится ... Итак, она не работает должным образом
Ciprian Mocanu
Вы правы, к сожалению. Я использую этот фрагмент только со структурой "один шаг назад" ...
gregmatys
10

Будьте осторожны, window.history.lengthпотому что он включает в себя также записи дляwindow.history.forward()

Таким образом, у вас может быть window.history.lengthболее 1 записей, но нет записей назад. Это означает, что ничего не произойдет, если вы стреляетеwindow.history.back()

Blitzlord
источник
9

Вы не можете напрямую проверить, используется ли кнопка «Назад». Вы можете посмотреть history.length>0, но это будет справедливо, если есть страницы впереди текущей страницы. Вы можете быть уверены, что кнопка «Назад» не работает, когда history.length===0.

Если это не достаточно хорошо, все, что вы можете сделать, это позвонить, history.back()и, если ваша страница все еще загружается после этого, кнопка Назад недоступна! Конечно , это означает , если кнопка назад находится в наличии, вы просто переходите от страницы. Вы не можете отменить навигацию в системе onunload, поэтому все, что вы можете сделать, чтобы остановить возвращение, - это вернуть что-то onbeforeunload, что приведет к появлению большого раздражающего запроса. Это того не стоит.

На самом деле это обычно действительно плохая идея - делать что-то с историей. История навигации для браузера Chrome, а не веб-страниц. Добавление ссылок «назад» обычно вызывает больше путаницы у пользователя, чем оно того стоит.

bobince
источник
2
Что касается длины - даже во всех браузерах. Некоторые браузеры считают текущую страницу элементом истории и начинаются с 1. Вы должны включить обнаружение браузера.
Макаден
На самом деле я думал, что так было всегда 1! 0Был brainfart, я думал , что браузеры всегда будет реагировать с 1или более. Оказывается, Opera и IE думают иначе - хороший улов.
bobince
1
«История навигации предназначена для браузера Chrome, а не веб-страниц» - Согласовано
Brian
5

history.lengthбесполезен, так как не показывает, может ли пользователь вернуться в историю. Также разные браузеры используют начальные значения 0 или 1 - это зависит от браузера.

Рабочим решением является использование $(window).on('beforeunload'события, но я не уверен, что оно будет работать, если страница загружается через ajax и использует pushState для изменения истории окна.

Поэтому я использовал следующее решение:

var currentUrl = window.location.href;
window.history.back();
setTimeout(function(){
    // if location was not changed in 100 ms, then there is no history back
    if(currentUrl === window.location.href){
        // redirect to site root
        window.location.href = '/';
    }
}, 100);
Gromo
источник
У меня работает так: function goBackOrTo (targetUrl) {var currentUrl = window.location.href; window.history.go (-1); setTimeout (function () {// если местоположение не было изменено в течение 800 мс, то история не возвращается, если (currentUrl === window.location.href) {// перенаправить в корневой каталог сайта window.location.href = targetUrl; }}, 800); }
alfonx
2

Я придумал следующий подход. Он использует событие onbeforeunload, чтобы определить, начинает ли браузер покидать страницу или нет. Если этого не произойдет в определенный промежуток времени, он просто перенаправит на запасной вариант.

var goBack = function goBack(fallback){
    var useFallback = true;

    window.addEventListener("beforeunload", function(){
      useFallback = false;
    });

    window.history.back();

    setTimeout(function(){
        if (useFallback){ window.location.href = fallback; }
    }, 100); 
}

Вы можете вызвать эту функцию, используя goBack("fallback.example.org").

Паскаль Расик
источник
1
Мне это нравится больше всего, я просто переключился windows.onbeforeunloadна прослушиватель событий, window.addEventListener("beforeunload", function (event) { useFallback = false; });чтобы он не перезаписывал window.onbeforeunload.
MiChAeLoKGB
2

Опираясь на ответ здесь и здесь . Я думаю, что более убедительный ответ - просто проверить, является ли это новой страницей в новой вкладке.

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

Иными словами, к ответам, связанным, мы не проверяем, referrerпоскольку на новой вкладке все еще будет реферер.

if(1 < history.length) {
    history.back();
}
else {
    window.close();
}
ATW
источник
1
Спасибо. Вы спасли мой день :).
Биджай Ядав
1

Есть еще одно почти идеальное решение, взятое из другого SO ответа :

if( (1 < history.length) && document.referrer ) {
    history.back();
}
else {
    // If you can't go back in history, you could perhaps close the window ?
    window.close();
}

Кто-то сообщил, что он не работает при использовании, target="_blank"но, похоже, у меня работает на Chrome.

Йонн Триморо
источник
0

в браузере есть кнопка «назад» и «вперед». Я придумаю решение по этому вопросу. но это повлияет на действие браузера вперед и вызовет ошибку в некоторых браузерах.

Это работает так: если браузер откроет новый URL, который никогда не открывался, то history.length будет расти.

так что вы можете изменить хэш, как

  location.href = '#__transfer__' + new Date().getTime() 

чтобы получить никогда не показанный URL, то history.length получит истинную длину.

  var realHistoryLength = history.length - 1

но, это не всегда работает хорошо, и я не знаю почему, особенно когда url auto jump быстро.

хончи ган
источник
0

Я пытался найти решение, и это лучшее, что я мог получить (но работает отлично, и это самое простое решение, которое я нашел даже здесь).

В моем случае я хотел вернуться к истории с помощью кнопки «Назад», но если первая страница, которую открыл пользователь, была подстраницей моего приложения, она вернулась бы на главную страницу.

Решением было, как только приложение загрузилось, я просто заменил состояние истории:

history.replaceState( {root: true}, '', window.location.pathname + window.location.hash)

Таким образом, мне просто нужно проверить, history.state.rootпрежде чем вернуться. Если это правда, я делаю вместо истории замену:

if(history.state && history.state.root)
    history.replaceState( {root: true}, '', '/')
else
    history.back() 
Maxwell sc
источник
Я не думаю, что есть другой хороший вариант использования. Возможно, это не очень хорошая идея, если вы хотите проверить историю за пределами вашего приложения.
Максвелл sc
-1
var fallbackUrl = "home.php";
if(history.back() === undefined)
    window.location.href = fallbackUrl;
Риджиш Прарат
источник
это выглядит супер просто ?! это проверено на различных браузерах?
benzkji
в Chrome history.back()есть undefinedтолько на пустой вкладке
gregmatys
-2

Решение

'use strict';
function previousPage() {
  if (window.location.pathname.split('/').filter(({ length }) => length > 0).length > 0) {
    window.history.back();
  }
}

Explaination

window.location.pathnameдаст вам текущий URI. Например https://domain/question/1234/i-have-a-problemдаст /question/1234/i-have-a-problem. См. Документацию о window.location для получения дополнительной информации.

Далее, вызов split()даст нам все фрагменты этого URI. так что если мы возьмем наш предыдущий URI, у нас будет что-то вроде ["", "question", "1234", "i-have-a-problem"]. См. Документацию о String.prototype.split () для получения дополнительной информации.

Вызов filter()здесь, чтобы отфильтровать пустую строку, созданную обратной косой чертой. В основном он вернет только фрагмент URI, длина которого больше 1 (непустая строка). Так что у нас было бы что-то вроде ["question", "1234", "i-have-a-question"]. Это можно было бы написать так:

'use strict';
window.location.pathname.split('/').filter(function(fragment) {
  return fragment.length > 0;
});

См. Документацию о Array.prototype.filter () и назначении Destructuring для получения дополнительной информации.

Теперь, если пользователь пытается вернуться во время работы https://domain/, мы не будем запускать оператор if и поэтому не window.history.back()будем запускать метод, чтобы пользователь оставался на нашем веб-сайте. Этот URL будет эквивалентен тому, []который имеет длину 0, и 0 > 0является ложным. Следовательно, молча терпит неудачу. Конечно, вы можете записать что-нибудь или выполнить другое действие, если хотите.

'use strict';
function previousPage() {
  if (window.location.pathname.split('/').filter(({ length }) => length > 0).length > 0) {
    window.history.back();
  } else {
    alert('You cannot go back any further...');
  }
}

Ограничения

Конечно, это решение не будет работать, если браузер не поддерживает History API . Проверьте документацию, чтобы узнать больше об этом, прежде чем использовать это решение.

Амин НАИРИ
источник
-5

Я не уверен, что это работает, и это полностью не проверено, но попробуйте это:

<script type="text/javascript">

    function goBack() {
        history.back();
    }

    if (history.length > 0) { //if there is a history...
        document.getElementsByTagName('button')[].onclick="goBack()"; //assign function "goBack()" to all buttons onClick
    } else {
        die();
    }
</script>

И где-то в HTML:

<button value="Button1"> //These buttons have no action
<button value="Button2">

РЕДАКТИРОВАТЬ:

Вы также можете исследовать, какие браузеры поддерживают функцию back (я думаю, что все они поддерживают) и использовать стандартный объект обнаружения браузера JavaScript, который подробно описан на этой странице . Тогда у вас может быть две разные страницы: одна для «хороших браузеров», совместимых с кнопкой «Назад», и одна для «плохих браузеров», предлагающих обновить их браузер.

Latze
источник
2
history.backэто функция. Вы хотите проверить, history.length > 0вернулись ли они тогда с помощьюhistory.back()
pixl coder
3
Также []в NodeList нет смысла, и вы не можете назначить строку для обработчика событий.
Бобинц
-8

Проверьте, window.history.lengthравен ли он 0.

Кристиан Санчес
источник
6
Не очень хороший способ, так как history.length не говорит вам, где вы находитесь в истории ...
Рон Рейтер
@ Рон Рейтер: Да, я думаю, что главный ответ и другие комментарии на этот вопрос уже установили, что более года назад ...
Кристиан Санчес