Статьи

Первый взгляд на API истории HTML5

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


Всегда представляйте одну и ту же информацию, когда пользователь обновляет страницу.

Объект history не новый; на самом деле, вы можете проследить его начало до ранних браузеров с 1990-х годов. Хотя он никогда не основывался на публичном стандарте, до HTML5, то есть каждый браузер поддерживал свою скудную, но иногда полезную функциональность. С момента своего создания объект history предоставляет средства для работы с историей конкретной вкладки в браузере (или в окне, прежде чем просмотр с вкладками стал нормой). Это иногда называют историей сеанса .

Старый объект history дал нам возможность программно перемещаться вперед и назад, что эквивалентно тому, как пользователь нажимает кнопки « Назад» и « Вперед» . Но HTML5 наконец обновляет API истории, добавляя возможность манипулировать URL браузера и поддерживать его состояние; хотя манипулирование URL-адресом в некоторой степени стало возможным с момента появления объекта location . Например:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
//On the URL: http://net.tutsplus.com/
 
//Get the full URL
location.href //»http://net.tutsplus.com/»
 
//Get the hash fragment
location.hash // «» (an empty string)
 
//Set the hash fragment
location.hash = «hello»
  
//Get the full URL
location.href //»http://net.tutsplus.com/#hello»
 
//Get the hash fragment
location.hash //»#hello»

Нативный API достаточно прост в использовании …

В некоторых веб-приложениях принято использовать «хэш-бэнгс» ( #! ). Они не только могут помешать браузеру переходить на другую страницу (облегчая управление динамическими веб-страницами), но также могут помочь в поисковой оптимизации (SEO) ( до недавнего времени Twitter широко использовал хэш-удары).

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

Техника проста: хранить информацию в URL, анализировать ее, а затем использовать Ajax для загрузки контента. Звучит замечательно, но есть много причин не использовать эту технику. Подвести итоги:

  • URL, такой как http://domain.com/#!1234 может не загружаться правильно, если JavaScript не включен.
  • У вас может быть два разных URL-адреса, указывающих на один и тот же контент (например, http://domain.com/#!1234 и http://domain.com/1234 ) — нет-нет для SEO.
  • Сервер не знает идентификаторов фрагментов .

API History помогает решить вышеупомянутые проблемы, предоставляя нам возможность преобразовывать URL-адреса, например с http://domain.com в http://domain.com/hello , без запуска обновления страницы. Ниже перечислены члены объекта history и их цели:

  • history.back() : переход к предыдущему URL в стеке истории.
  • history.forward() : переход к следующему URL-адресу в стеке истории.
  • history.go() : Переходит к URL-адресу по указанному индексу в стеке истории. например history.go(-2)
  • history.pushState() : добавляет URL-адрес в стек истории с указанным состоянием. например history.pushState({ foo : "bar"}, "New title", "new-url.html") , где первый аргумент является объектом состояния.
  • history.replaceState() : Обновляет (а не добавляет) текущий URL в стеке истории с предоставленной информацией о состоянии. например history.replaceState({ foo : "bar"}, "New title", location.href)
  • history.length : возвращает количество URL в стеке истории.
  • history.state : возвращает объект состояния в верхней части стека истории.

В следующем примере не используются внешние библиотеки:

1
2
3
4
5
6
7
<nav>
  <ul>
    <li><a href=»/history/example/index.html»>Home</a></li>
    <li><a href=»/history/example/hello.html»>hello</a></li>
    <li><a href=»/history/example/about/index.html»>About</a></li>
  </ul>
</nav>
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
// NodeLists do not have a forEach method
[].forEach.call(document.querySelectorAll(«nav a»),function(e) {
    e.addEventListener(«click», function(evt) {
      var title = this.textContent;
      var url = this.href;
 
      //Change the URL
      history.pushState(null, title, url);
 
      //Do some ajax stuff
 
      //Prevent the browsers default behaviour of navigating to the hyperlink
      evt.preventDefault();
    })
});

Нативный API достаточно прост в использовании, но вы можете найти множество библиотек, которые очень помогают с общими шаблонами перехвата ссылки, загрузки данных через Ajax и вставки данных на страницу. Две популярные библиотеки — это pjax и History.js .


Как и в случае с любой технологией или API, учитывайте лучшие практики. Давайте рассмотрим несколько лучших практик при использовании API истории.

Не меняйте URL только потому, что можете; меняйте его только тогда, когда это имеет смысл!

Например, предположим, что ваш интернет-магазин находится по адресу https://shop.domain.com/ , а на главной странице отображается список популярных товаров. Нажатие на один из пунктов может открыть модальное окно , содержащее информацию о продукте (конечно, полученную через Ajax). Вам не нужно менять URL при этом; вместо этого вы можете указать ссылку на продукт в модальном окне, которая приведет пользователя на страницу продукта.

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

Chrome Web Store меняет свой URL при отображении различных элементов. При переходе из / webstore / category / Popular в / webstore / detail / pjkljhegncpnkpknbcohdijeoejaedia обновление страницы не происходит.

Загружайте только то, что необходимо.

К сожалению, старые браузеры не поддерживают pushState() и replaceState() . Поэтому важно убедиться, что и ваша страница, и пользовательский интерфейс (UX) не нарушены в этих браузерах. Используйте проверенную и верную концепцию прогрессивного улучшения .

Распространенным вариантом использования может быть перехват события щелчка ссылки и использование Ajax для загрузки содержимого в новом окне при одновременном изменении URL-адреса. Убедитесь, что ссылки работают нормально без JavaScript ; у элемента привязки должен быть действительный URL в атрибуте href . Затем для браузеров, которые поддерживают новые возможности, код JavaScript будет извлекать содержимое URL через Ajax. Вот как может выглядеть этот код:

1
2
3
4
5
6
7
//Using jQuery (would work fine with raw javascript)
if («pushState» in history) {
    $(«nav a»).on(«click», function() {
        history.pushState(null, this.textContent, this.href);
        return false;
    });​
}

Ajax замечательный, и может быть соблазнительно пойти по легкой дороге и загрузить весь HTML-документ для отображения в модальном окне. Не делай этого! Загрузка ненужных данных может сказаться на UX, особенно на медленных соединениях.

Потратьте дополнительное время, чтобы убедиться, что ваше приложение не тратит байты по проводам, даже если это означает, что вы тратите дополнительное время на свой внутренний код. Вы можете отправить собственный заголовок HTTP, который указывает, что сервер должен обслуживать только минимальное содержимое (например, JSON, фрагменты HTML и т. Д.).

01
02
03
04
05
06
07
08
09
10
/* Note server support for HTTP_X_REQUESTED_WITH may vary, also it may be worth sending your own custom header in the case that the JavaScript doesn’t send the header you expected */
if(isset($_SERVER[‘HTTP_X_REQUESTED_WITH’]) && strtolower($_SERVER[‘HTTP_X_REQUESTED_WITH’]) == ‘xmlhttprequest’) {
    //Ajax request
    echo «Content without lots of crazy markup»;
}
else {
    //Non-ajax request
    include(‘header.php’);
    …
}

Демо демонстрирует это. Нажмите на cat.php в Примере 4, и вы увидите, что в ответе отправляется только необходимый контент.

Помните о лучших практиках.

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

Когда вы изменяете URL-адрес с помощью pushState() с http://domain.com на http://domain.com/contact , ваш веб-сервер может искать каталог с именем contact или файл с именем contact.html . Важно, чтобы URL-адреса, которые вы используете с API истории, были реальными URL-адресами, на которые отвечает ваш сервер.

Есть много структур, которые могут обрабатывать маршрутизацию для вас; Стоит использовать один, если вы можете.

Github использует pushState() для семантически разных частей контента; их содержимое выглядит одинаково при обновлении страницы.

Убедитесь, что и ваша страница, и пользовательский интерфейс (UX) не нарушены в этих браузерах.

Событие popstate срабатывает каждый раз, когда изменяется текущая запись истории. Используйте это событие для согласованного UX.

Например, предположим, что вы используете Ajax для загрузки контента с членами вашей команды. URL может выглядеть как http://domain.com/team/person1 . Затем пользователь нажимает на ссылку «Далее» в пользовательском интерфейсе, которая загружает информацию о лице 2 ( http://domain.com/team/person2 ). Если пользователь затем нажимает кнопку « Назад» в браузере, информация о лице 1 может не загружаться автоматически. Вы можете получить информацию о состоянии и отобразить информацию о лице 1.

Еще раз, обязательно загружайте только то, что необходимо . Если информация о лице 1 уже загружена, вам не нужно запрашивать ее снова. Показать и скрыть элементы DOM при необходимости. Вы также можете передавать объекты состояния в pushState() для поддержания состояния.

1
<article data-person-id=»1234″>…</article>
1
2
3
4
5
6
7
8
9
var personId = ‘1234’;
/*
* jQuery selector
* If the html fragment for personId is found, we should show it
*/
var person = $(«.person[data-person-id=»+personId+»]»);
if ( person && person.length > 0 ) {
    person.show();
}

Информативный сайт caniuse.com имеет отличную реализацию (за исключением хеш-фрагментов!) Для обработки кнопки « Назад» . Попробуйте это. Отредактируйте текст в поле поиска и нажмите « Назад» . Подсказка: обратите внимание на задержку обновления в адресной строке. Эта задержка предотвращает постоянное обновление URL-адреса при каждом нажатии клавиши, в отличие от менее частых обновлений, когда вы заканчиваете ввод поискового запроса.

Метод pushState() добавляет запись в стек истории; тогда как replaceState() заменяет текущую запись. Например, предположим, что вы изменяете URL-адрес при каждом нажатии клавиши в текстовом поле. «Нажатие» на новое состояние добавляет запись в историю каждый раз, когда пользователь отправляет эти данные; это не лучшее решение, потому что пользователю нужно будет нажимать кнопку « Назад» для каждой буквы. replaceState() этого используйте replaceState() , вот так:

1
<input type=»text» id=»search» />
1
2
3
$(«#search»).keyup(function() {
  history.replaceState(null, null, «search?=» + $(«#search»).val());
});

Естественно, это всего лишь верхушка айсберга. В Интернете существует множество методов, шаблонов и библиотек, которые работают с API истории HTML5. Хотя я не могу охватить все аспекты истории API, я могу предоставить вам различные ресурсы для расширения ваших знаний.