Сохранение навигации по истории при использовании Ajax

Динамическая подгрузка контента страницы асинхронными запросами — это очень удобно — при этом экономится время загрузки и траффик, браузер перегружает не всю страницу целиком, а только определенную часть. Реализован такой подход может быть в применении фильтров каталога, показе работ портфолио, проигрывании слайд-шоу фотогалереи.

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

При работе с фреймворком jQuery можно попробовать поискать плагины, решающие эту проблему. Однако, сегодня мы попробуем написать решение самостоятельно. Возможно, оно не будет супер-унивирсальным, зато оно будет компактным, мы познакомимся с принципом решения проблемы и будем иметь полный контроль над скриптом — в случае исключений нам не придется разбирать чужой код.

Объект history в браузерах защищен от просмотра содержимого и его модифицирования. Это сделано для того, чтобы посещения пользователя нельзя было подсмотреть. Все, что доступно javascript-коду — навигация по объекту history и данные о его длине. Поэтому как-то обмануть браузер и напрямую добавить наши асинхронные переходы в историю посещений не получится. Значит надо совершить эти переходы, но так, чтобы они были не заметны пользователю. Для этого мы будем осуществлять ajax-запросы через скрытый плавающим фрейм, подставляя в его атрибут src строку с нужными параметрами.

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

$.post( url, { param1: value1, param2: value2 }, function( data ){ alert( data ); });

т.е. посылали методом POST переменные param1 и param2 со значениями value1 и value2 соответственно на адрес url, и при ответе выводили его содержимое во всплывающем окне.

Вместо этого запрос будем осуществлять иначе:

$( 'iframe#history_frame' ).attr( 'src', url + '?param1=' + value1 + '&param2=' + value2 );

а получать данные так:

$( 'iframe#history_frame' ).load( function(){
	var data = $( this ).contents().find( 'body' ).html();
	alert( data );
});

Здесь iframe с идентификатором history_frame является скрытым плавающим фреймом, через который мы осуществляем обмен данными с сервером. При получении ответа, событие onload запустит наш обработчик, который выдаст нам ответ от сервера.

Вставьте в код страницы фрейм и попробуйте:

<iframe id="history_frame" name="history_frame" src="about: blank;" style="display: none;">

В некоторых браузерах, к сожалению, событие onload может не срабатывать. Для решения этой проблемы отправку запросов и назначение обработчика события onload у iframe будем выполнять после загрузки объекта window

$( window ).load( function() { 
	$( '#history_frame' ).attr( 'src', url + '?param1=' + value1 + '&param2=' + value2 ); 
	$( '#history_frame' ).load( function() {
		var data = $( this ).contents().find( 'body' ).html();
		alert( data );
	}
});

Попробовав, вы можете убедиться, что теперь Ajax-переходы фиксируются в истории браузера, но есть неприятный момент - они фиксируются дважды. Чтобы избежать повтора исключим из html-кода страницы код фрейма и будем его динамически создавать средствами javascript:

$( '<iframe src="about:blank" id="history_frame" name="history_frame" style="display: none;"/>' ).appendTo( 'body' );

Все. Решение для фиксации Ajax-переходов в истории браузеров готово - всего 4 строчки кода и небольшая модификация вашего скрипта. Решение проверено в IE 6,7,8,9, Opera 11, Safari 4, Firefox 3.5,4, Google Chrome 10. Демо можно посмотреть здесь.

Комментарии (2)
  • Сергей
    |
    20.03.2016, 12:51
    Здравствуйте! Что-то не получилось с таких подходом реализовать это с постраничной навигацией на jquery. Мне надо было, чтобы после перехода, скажем на 7-ю страницу и нажав на обычную ссылку документа, можно было бы нажав на стрелку назад, вернуться обратно к 7-й странице, по сути как раз то, что описывается в статье, но с этим примером не получалось, возвращалось на 1-ю страницу, а не на 7-ю. Позже пришла мысль, создать невидимый инпут, в который заносить номер страницы на которую перешли, а при инициализации постраничной навигации брать значение для переменной page из скрытого импута, а при клике на номер страницы заносить номер в этот импут, и вуаля - всё заработало) Очень рад)
Комментировать
Обновить проверочный код