Theory and Tasks for Students - Spring 2019
Одностраничные веб-сайты

В стандартном случае, при настройках веб-сервера по умолчанию, веб-сайт представляет собой весьма простую вещь - набор файлов HTML документов, находящихся в корневой директории сайта и поддиректориях. Например, если корневой директорией сайта example.com является /var/www/test/, то запрос к example.com/foo/bar.html переводится в запрос к файлу /var/www/test/foo/bar.html. При запросе к директории, веб-сервер вернет файл index.html в этой директории, либо отобразить страницу со списком файлов. Это означает, что каждая страница сайта должна представлять собой полноценный документ, вместе с шапкой, навигацией и другими элементами, которые, скорее всего, будут одинаковым для всех страниц - таким образом дублируется код. Это также вызывает неудобства при необходимости что-либо поменять в одном таком элементе - придётся вносить изменения в каждый файл каждой страницы.

В случае достаточно простого сайта, можно сделать следующее - одну страницу, содержащую все неизменные элементы и пустые контейнеры для содержания остальных страниц - собственно, остальные файлы должны содержать только содержание для контейнера, без всего лишнего, таким образом они не будут являться полноценными HTML документами. При переходе по ссылкам из навигации можно не производить переадресацию и полное открытие нового документа, а подгружать его содержание с помощью AJAX в контейнер. Это можно реализовать двумя способами - с помощью hash части адреса (после символа #, http://example.com/#news), либо с помощью объекта window.history, позволяющим полностью менять содержание адресной строки в пределах того же протокола, порта и домена/поддомена.

document.location.hash

В этом случае ссылки должны иметь вид <a href="#news"></a>, при нажатии на них будет только изменяться хеш-часть адреса без переадресации. Эти изменения можно перехватывать событием hashchange у объекта window. Узнать текущий адрес можно через document.location.href, но также можно получить и значение хеша отдельно через document.location.hash - важно помнить, что хешом является вся подстрока адреса, начиная с самого левого символа #, т.е. для адреса http://example.com/#news#other хешом будет #news#other. При обработке события изменения хеша ваш скрипт должен будет определить по текущему хешу документ по какому адресу необходимо подгружать, для этого можно либо хранить объект соответствий хешей и адресов, либо хеш можно однозначно транслировать в адрес к документу как если бы это был традиционный адрес. Ещё важно не забывать подгружать правильный контент при первом открытии страницы.

window.history

В таком подходе необходимо использовать два события - нажатия на ссылки навигации или вовсе любой переход по внутренним ссылкам, и, для полного контроля, изменения состояния истории - popstate у window. При нажатии на ссылки обработчик события должен предотвратить переадресацию, что является "поведением по умолчанию", с помощью функции e.preventDefault(): $("a").on("click", function(e) { e.preventDefault(); window.console.log($(e.target).attr("href")); // будет выводить в консоль адрес ссылки }); В обоих событиях снова нужно будет собирать из целевого пути адрес документа для загрузки через AJAX. Единственный недостаток этого метода в том, что при изменении адреса пользователем вручную всегда будет производиться переадресация, что может привести к попытке открыть документ по несуществующему адресу. Например, по нажатию на ссылку навигации "Новости" скрипт изменил адрес с http://example.com на http://example.com/news (что также изменило значение document.location.href), однако при открытии этого адреса отдельно сервер, скорее всего, вернёт ошибку 404 Not Found, так как на сервере нет файла /var/www/test/news, а даже если бы был, он бы не содержал статические элементы, которые описаны только в index.html. Этого можно избежать, сделав переадресацию (почти) всех запросов к корневому файлу index.html с помощью конфигурационного файла сервера - этот механизм будет рассмотрен позже.