18 May 2012

HTML5 History API уже сегодня и без ограничений

Website developmentJavaScriptAPI

Библиотека для работы HTML5 History API


Изначально этот проект был задуман добавить поддержку HTML5 History API в старые HTML4 браузеры. Первые версии библиотеки были нацелены именно на эти потребности, но с учетом прошедшего времени и пожеланий многоуважаемых разработчиков использующих эту библиотеку, она выросла до уровня того, что выполняет некие промежуточные действия по добавлению/исправлению того функционала что описаны в спецификациях по интерфейсу History.

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

Использование.

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

Приведу небольшой пример:
<!DOCTYPE html>
<html>
    <head>
        <script type="text/javascript" src="history.js"></script>
        <script type="text/javascript">
            window.onload = function() {

                // просто функция добавляет DIV с нужным нам текстом
                function appendText( text ) {
                    var div = document.createElement( "div" );
                    div.innerHTML = text;
                    document.body.appendChild( div );
                }

                // функция для ссылок обрабатывается при клике на ссылку
                function handlerAnchors() {

                    // заполним хранилище чем нибудь
                    var state = {
                        title: this.getAttribute( "title" ),
                        url: this.getAttribute( "href", 2 ) // двоечка нужна для ИЕ6-7
                    }

                    // заносим ссылку в историю
                    history.pushState( state, state.title, state.url );

                    // тут можете вызвать подгруздку данных и т.п.
                    // ...

                    appendText( '<b>Вы перешли по ссылке:</b> ' +
                                    '<span style="color: green;">' + state.url + '</span>' );

                    // не даем выполнить действие по умолчанию
                    return false;
                }

                // ищем все ссылки
                var anchors = document.getElementsByTagName( 'a' );

                // вешаем события на все ссылки в нашем документе
                for( var i = 0; i < anchors.length; i++ ) {
                    anchors[ i ].onclick = handlerAnchors;
                }

                // вешаем событие на popstate которое срабатывает
                // при нажатии back/forward в браузере
                window.onpopstate = function( e ) {

                    // просто сообщение
                    appendText( '<b>Вы вернулись на страницу:</b> ' +
                        '<span style="color: green;">' + history.location + '</span>' +
                        '<br/><b>state:</b> <span style="color: green;">' +
                        JSON.stringify( history.state ) + '</span><br/><br/>' );

                    // тут можете вызвать подгруздку данных и т.п.
                    // ...
                }
            }
        </script>
    </head>
    <body>
        <h1>Переходите по ссылкам, а затем жмите в браузере кнопки back/forward</h1>
        <a href="/mylink.html" title="Заголовок связанный с ссылкой My Link">My Link</a>
        <a href="/otherlink.html" title="Заголовок связанный с ссылкой Other Link">Other Link</a>
    </body>
</html>

Как видите, ничего сложного в использовании этой библиотеки нет, из примера выше вы, наверное, заметили, что разница/отличия использования методов описанных в спецификации по интерфейсу History практически отсутствуют. Имеется лишь одна небольшая разница в том, что получение текущей ссылки при срабатывании события popstate, мы получаем из объекта history.location.

Как это работает.

В браузерах HTML5 она выполняет лишь роль исправления багов/ошибок при работе с историей. А ссылки имеют нормальный приятный вид, без использования каких либо hash-fallback.

В браузерах HTML4, конечно же, используется hash-fallback, ибо другого варианта для таких браузеров, конечно же, нет. Но для разработчика внутри JavaScript-кода это не будет являться каким-то недугом, потому как ссылки будут иметь тот вид, что изначально задуманы. И вам не нужно где либо, прописывать hash-ссылки и/или соблюдать правила для поисковиков, что бы те в свою очередь нормально индексировали сайт. Ведь ссылки будут нормального вида, а значит поисковый робот, спокойно перейдет по нужной ссылке.

Функционал библиотеки.

Библиотека имеет небольшие тонкости при работе с ней. Как мы уже заметили, у библиотеки есть собственный объект history.location, он ничем не отличается от известного объекта window.location. То есть одним словом это и есть ссылка на объект window.location за исключением того что в браузерах HTML4 он перехватывает getters/setters у оригинального объекта, делает нужные модификации и возвращает результат.

Способ работы с history.location ничем не ограничен, вы так же можете его назначать, получать, обращаться к его свойствам и т.д.

К примеру, это выглядит так:
    history.location = "http://yandex.ru/"; // произойдет переход на страницу Яндекса.
    history.location.hash = "#newhash";  // просто сменим hash на странице.
    // и так далее по всем свойствам, описанным
    // в спецификации по интерфейсу Location

Следующая тонкость библиотеки это его настройка под ваши нужды. Библиотека не имеет каких-то объектов для настройки, а получает их из параметра GET при подключении библиотеки через HTML-элемент script, то есть считывает ссылку при подключении скрипта к сайту.

Выгладит это примерно так:
<script type="text/javascript" src="history.js?type=/&redirect=true&basepath=/pathtosite/"></script>

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

Параметр: type

Особой роли не играет, он нужен для украшения ссылки в браузерах HTML4. В этом параметре вы можете указать совершенно любую строку/символ, который будет добавлен после знака # (hash), тем самым вы просто украсите ссылку нужным знаком/текстом. К примеру, если я задам этому параметру текст: «HelloWorld/», то ссылки будут иметь эту подстроку. Допустим кликнув по ссылке http://somesite.com/folder/page.html мы получим ссылку вида: http://somesite.com/#HelloWorld/folder/page.html. Вы можете поэкспериментировать с этим параметром. По умолчанию в библиотеке этот параметр имеет подстроку "/" (слеш).

Параметр: basepath

Один из важных параметров, именно по этому параметру библиотека формирует ссылку для объекта history.location. Он указывает, где находиться корень сайта, обычно сайты лежат прямо в корне домена, но иногда бывает нужно сайт положить в иную папку от основного домена. Для этого и был добавлен этот параметр, что бы сайты, находящиеся вне корня могли полноценно работать в браузерах HTML4.

Параметр: redirect

Этот параметр отвечает за переадресацию сайта при переходе по ссылке, скопированной в браузере HTML4 в браузер HTML5. Она просто перенаправляет пользователя перешедшего по ссылке вида: http://somesite.com/#/folder/page.html на ссылку вида http://somesite.com/folder/page.html и наоборот, если пользователь перешел по ссылке из браузера HTML5 в браузер HTML4. Важно помнить, что этот параметр тесно связан с параметром basepath, так как именно по этому параметру он делает выводы, куда перенаправить пользователя.

Заключение.

В заключении хочу добавить, что иногда порой нужно узнать в каком браузере мы находимся, в браузере HTML4 или в браузере HTML5. Для этих целей я добавил свойство emulate в объект window.history указывающее на то происходит эмуляция или нет. Если это свойство имеет значение true, значит, мы находимся в браузере HTML4 и работаем с hash-ссылками, в противном случае иное.

Так же добавлю, что в браузерах HTML5 библиотека исправляет баги/недоделки интерфейса History и все что с ним связано. К примеру, в Safari добавляет объект state в интерфейс History, в браузерах Safari и Chrome убирает initial state (срабатывание события popstate при первой загрузке документа).

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

Библиотека работает с совершенно любыми фреймворками, и не использует их для своих целей.

Библиотека была протестирована в браузерах:
IE 6+
FireFox 3+
Opera 11+
Opera Mobile 11+
Chrome 17+
Safari 5+


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

Все пожелания, вопросы, отчеты о багах и т.д. вы можете мне посылать на почту, указанную на ГитХабе или написать в разделе Issues на ГитХабе.

Скачать и посмотреть данную библиотеку вы можете на GitHub: https://github.com/devote/HTML5-History-API

Так же можете посмотреть работоспособность библиотеки на моем, к сожалению не доделанном сайте: http://history.spb-piksel.ru/. Сам сайт не доделан, но работоспособность библиотеки вы можете на нем посмотреть.

UPD(12.09.2012): Важно! Мне часто стали писать/сообщать о неработоспособности библиотеки в ИЕ9. Проблема связана с тем, что ИЕ9 капризный браузер и придирается ко всем мелочам. Как выяснилось, многие разработчики что используют скрипты взятые с GitHub сталкиваются с проблемами их неработоспособности, потому что ИЕ9 при подключении скриптов ожидает получить заголовок application/javascript, но GitHub возвращает заголовок text/plain. Поэтому подключать скрипты напрямую с GitHub не рекомендуется. Скачайте скрипт к себе на хост и используйте.
Tags:HTML5 History APIнавигация по сайтуhash-навигация
Hubs: Website development JavaScript API
+83
60.5k 612
Comments 49
Popular right now
Back-end разработчик (Laravel, REST API)
from 100,000 to 140,000 ₽GBMSRemote job
Java API Developer
from 3,300 to 5,000 $AWWCOR Inc.Remote job
Frontend developer
from 200,000 ₽VMS SoftwareСанкт-ПетербургRemote job
Frontend-разработчик
to 200,000 ₽WEBINARМосква
Top of the last 24 hours