Сохранение навигации по истории при использовании 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 + '¶m2=' + 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 + '¶m2=' + 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. Демо можно посмотреть здесь.