Pull to refresh

Hash-навигация в AJAX-сайтах

Reading time2 min
Views26K
Если вы строите ajax-cайт, то рано или поздно, вы сталкиваетесь с проблемой «не работает кнопки назад-вперед в браузере». Потому что ajax — асинхронный, он не выполняет переход на другие страницы, а всего-лишь меняет некую часть содержимого на текущей.

Вторая проблема, с которой борются все разработчики — проект перед сдачей в продакшн просто изобилирует кучами javascript (ajax) кода. Весь этот код по своей сути — всего лишь запросы страниц с севера «без шаблона», т.e., чистое содержимое страницы.

Если первая проблема — проблема для пользователей, то вторая — для разработчиков. Ниже я постараюсь описать, как решаются обе задачи весьма элегантным способом. По очень похожей методике строятся ссылки на facebook и twitter.

Конечно, разработчику хочется, чтобы он не думал по ajax, но его проект получался full-ajax :-) Поэтому, если разработчик пишет ссылку:

<a href="/contacts/">Contacts</a>


то она автоматически должна быть заменена на ajax-овую. Но чтобы контролировать ajax/не_ajax — лучше ко всем ссылкам в коде дописывать специальный класс, например:

<a href="/contacts/" class="EngineAJAX">Contacts</a>


После загрузки DOM-модели (событие dom:loaded) нужно найти все ссылки — убрать у них класс EngineAJAX и дописать им в href "#!". В итоге ссылка получится вида:

<a href="#!/contacts/">Contacts</a>


Т.е., теперь наша ссылка — «якорная». При переходе на такую ссылку браузер не перегружает страницу, а пытается найти элемент с указанным ID и позиционироваться на него.
Думаю понятно, что ajax-запрос нужно выполнять именно при переходе на такого рода ссылку. К сожалению, отловить событие document.location.hash onChange невозможно, поэтому на весь документ прийдется вешать обработчик onClick и «слушать», по какому элементу кликнули.

Половина головоломки решена: при клике на ссылку выполняется переход на якорь, клик ловится, выполняется ajax. Чтобы кнопки вперед-назад работали в браузере, нужно в вечном цикле проверять, не поменялся ли document.location.hash, и если поменялся — то выполнять ajax-запрос. Проблема #1 для юзера — решена.

Теперь немного о проблеме #2, или о том-же ajax'e, который должен доставать с сервера «чистый контент страницы». Все зависит от движка или CMS, которую вы используете. В движок любым приятным для вас способом нужно дописать такую возможность: если передан определенный параметр (например, GET параметр notemplate=1), то движок должен выдать содержимое страницы «без шаблона». Тоесть, для приведенного выше примера ajax-запрос всего-лишь стукнется в URL:

/contacts/?notemplate=1

И-так, проблемы #1 и #2 — почти решены. Почти, потому что появилась проблема #3: после выполнения любого ajax'a html-код всего документа меняется, и в нем могут появится новые ссылки с классом EngineAJAX, которые требуют преобразования в «якоря». Проблему усугубляет еще то, что события типа dom:changed не существует. Единственный вариант «в лоб», который я придумал — это 10 раз в секунду проверять, не поменялось ли содержимое тега body (+1 вечный цикл) — и если поменялось — проходить по всем ссылкам и пытаться их преобразовать (именно поэтому, мы убирали класс EngineAJAX из обработанных ссылок — чтобы повторно по ним не идти).

P.S.: в jQuery есть событие onHashChanged и вроде-бы onDomChanged, но я думаю в jQuery отлов подобных cобытий все-равно сведется к вечным циклам.
Tags:
Hubs:
+4
Comments29

Articles