Статьи

Выборочная загрузка контента

Один из методов, о которых мы говорим в адаптивном веб-дизайне Jump Start, называется Выборочная загрузка контента (SCL). Этот метод действительно полезен в ситуациях, когда вы хотите загружать небольшие фрагменты данных в уже загруженную страницу в структурированном виде. Когда это будет полезно?

  • Если у вас есть серьезные проблемы с пропускной способностью между вашим сервером и устройством конечного пользователя (например, на мобильном соединении, которое перемещается по плохой сети с большим количеством ошибок и вынужденным иметь дело с передачей обслуживания соты).
  • Когда ваши страницы в основном одинаковы по структуре от страницы к странице, и простая перезагрузка контента экономит много запросов.
  • Если вы аккуратно разбили содержимое на части и хотите просто загрузить следующий фрагмент в последовательности (например, бесконечная прокрутка в ленте Twitter)

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

Если на вашу страницу добавлено только несколько дополнительных битов данных (например, твит) или изменяется только небольшое количество контента (например, подробности о продукте), тогда SCL может быть хорошим вариантом для вас. Это работает не во всех обстоятельствах, а также вызывает ряд возможных проблем с URL-адресами, историей браузера и тем, что контент попадает на «страницу» поисковыми системами (если это важно для вас).

Повторяя наш подход из Jump Start RWD, это то, что мы собираемся сделать концептуально:

  • По первому запросу страницы мы загрузим все содержимое страницы, включая навигацию по сайту, макет содержимого, файлы CSS и JS, как обычно.
  • После загрузки страницы мы переопределим все ссылки на нашей странице, чтобы сделать их XHR, а не стандартным запросом документа.
  • Затем мы обработаем ответ (ответ XHR будет только внутренним содержимым страницы в JSON, а не всей страницей) и перезапишем содержимое, которое было на странице.
  • Затем мы можем использовать pushState() для изменения истории нашего браузера (чтобы URL обновлялся до чего-то общего, и мы можем вернуться назад, если потребуется).

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

Мы собираемся настроить страницу, которая может загружать контент о книгах без необходимости перезагружать всю страницу, только соответствующий контент. Мы также будем использовать pushState() из History API, чтобы гарантировать, что если пользователь захочет поделиться или вернуться к URL, он сможет это сделать.

Чтобы упростить процесс выражения, мы будем использовать jQuery для манипулирования DOM и библиотеку шаблонов JavaScript под названием Handlebars.js . Если вы еще не ознакомились с опциями шаблонов JavaScript и тем, что они могут сделать, Handlebars — отличный выбор, чтобы промокнуть.

В основе нашего решения лежит тот факт, что URL-адреса могут отвечать по-разному в зависимости от того, являются ли они XHR или обычным HTTP-запросом. Если сервер получает обычный запрос, то представление доставит полный HTTP-ответ (содержащий весь документ, а затем JS, CSS и т. Д.). Если сервер получит XHR, он ответит JSON, который содержит только данные о запрошенной книге.

Так, например, стандартный HTTP-ответ для страницы «Франкенштейн» выглядит следующим образом:

  <! DOCTYPE html>
 <HTML>
 <Голова>
   <script type = "text / javascript" src = " https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js "> </ script>

 var original = null;
 var backtostart = true;

   <script type = "text / javascript">
       ($ (документ) .ready (function () {
           var source = $ ("# story-template"). html ();
           var template = Handlebars.compile (источник);

           var story_link_handler = (function (evt) {
               evt.preventDefault ();
               $ .get (this.href, function (data) {
                   $ ( "# Contentarea") HTML ( "").
                   $ ( "# Contentarea") HTML (шаблон (данные)).
                   history.pushState ({url: data.location}, data.title, data.location);
               }, "JSON");
           });

           $ ("ul # storylist li a"). bind ("click", story_link_handler);

           $ (window) .bind ("popstate", function (evt) {
               if (event.state) {
                   url = event.state.url;
                   $ .get (url, function (data) {
                       $ ( "# Contentarea") HTML ( "").
                       $ ( "# Contentarea") HTML (шаблон (данные)).
                   }, "JSON");
                backtostart = false;
               } еще {
                if (! backtostart) {
                   backtostart = true;
                       $ ( "# Contentarea") HTML ( "").
                       $ ( "# Contentarea") HTML (оригинал).
                } еще {
                  original = $ ("# contentarea"). html ();
                     backtostart = false;
                }
             }
           });

       }));
   </ Скрипт>
 </ HEAD>
 <Тело>
   <ul id = "storylist">
       <li> <a href="mobydick"> Моби Дик </a> </ li>
       <li> <a href="gulliverstravels"> Путешествия Гулливера </a> </ li>
       <li> <a href="frankenstein"> Франкенштейн </a> </ li>
   </ UL>
   <div id = "contentarea">
       <article id = "story">
           <H1> Франкенштейн </ h1>
               <h2> Мэри Шелли </ h2>
               <p> Доктор создает искусственную жизнь </ p>
           </ Статьи>
       </ DIV>
 <script type = "text / javascript" src = "handlebars.js"> </ script>
       <script id = "story-template" type = "text / x-handlebars-template">
       <Статья>
           <H1> {{название}} </ h1>
           <H2> {{автора}} </ h2>
           <Р> {{синопсис}} </ р>
       </ Статьи>
       </ Скрипт>
   </ Body>
 </ Html> 

Примечание: вы можете скачать код, использованный в этой статье, в zip-файле, указанном в конце этой статьи.

Однако эквивалентный ответ JSON для XHR будет выглядеть следующим образом:

  {
   "местоположение": "/ Франкенштейн",
   "title": "Франкенштейн",
   "автор": "Мэри Шелли",
   «Синопсис»: «Безумный доктор создает искусственную жизнь»
 } 

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

  <script id = "story-template" type = "text / x-handlebars-template">
       <Статья>
           <H1> {{название}} </ h1>
           <H2> {{автора}} </ h2>
           <Р> {{синопсис}} </ р>
       </ Статьи>
   </ Скрипт> 

Примечание: вы можете скачать код, использованный в этой статье, в zip-файле, указанном в конце этой статьи.

Handlebars использует элемент script для создания шаблона для того, как будет выглядеть статья (этот контент не будет отображаться браузером, так как он не будет предпринимать действия в отношении его типа). Расположение переменных определяется с использованием синтаксиса {{variable}} . Вы можете сделать намного больше с Handlebars (условные выражения, циклы, выполнение блоков и т. Д.), Которые мы не используем в этом случае. Запишите идентификатор скрипта, он нам нужен, чтобы мы могли передать его в компилятор шаблона Handlebars.

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

  var source = $ ("# story-template"). html ();
   var template = Handlebars.compile (источник); 

Далее мы определяем функцию, которую мы можем использовать для нашей ссылки обработчик события onclick . Здесь мы просто останавливаем фактический запрос к файлу, предотвращая его поведение по умолчанию. Оттуда мы создаем JQuery XHR, который возвращает JSON по URL, который был определен в HREF ссылки.

  var story_link_handler = (function (evt) {
       evt.preventDefault ();
       $ .get (this.href, function (data) {
           $ ( "# Contentarea") HTML ( "").
           $ ( "# Contentarea") HTML (шаблон (данные)).
           history.pushState ({url: data.location}, data.title, data.location);
       }, "JSON");
   }); 

Когда ответ возвращается, мы просто перезаписываем область содержимого div которая содержит все данные нашей книги.

  $ ( "# Contentarea") HTML (шаблон (данные)). 

Мы также используем pushState() чтобы pushState() только что запрошенный URL в историю браузера, чтобы мы могли вернуться назад, используя кнопку назад.

  history.pushState ({url: data.location}, data.title, data.location); 

Это не совсем pushState() картина с pushState() , однако, для того, чтобы он «просто работал» для пользователя. Затем мы создаем popstate события popstate в окне, чтобы, когда пользователь popstate кнопку «Назад», мы могли обновлять содержимое соответствующими данными для книги. В этом случае мы собираемся и получаем данные снова, используя XHR. С помощью pushstate можно хранить данные в объекте state . В нашем случае объем данных невелик, и не рекомендуется загружать в браузер пользователя дополнительные данные (особенно на мобильные устройства), поэтому делайте это только в том случае, если вы можете гарантировать, что это небольшое количество.

  $ (window) .bind ("popstate", function (evt) {
       if (event.state) {
           url = event.state.url;
           $ .get (url, function (data) {
               $ ( "# Contentarea") HTML ( "").
               $ ( "# Contentarea") HTML (шаблон (данные)).
           }, "JSON");
       }
   }); 

Одна из вещей, которую мы должны рассмотреть с этой техникой, — это то, что происходит, когда браузер возвращается к началу списка. То есть вы вытолкнули все свои XHR из стека и вернулись к тому, с чего начали.

Чтобы исправить это, мы используем флаг, чтобы определить, вернулись ли мы к началу или нет, и мы сохраняем контент, который был в #contentarea чтобы мы могли его заменить. Вы можете использовать другие методы, например, просто скрыть область исходного содержимого или сохранить JSON исходного документа.

Затем мы обновляем событие popstate чтобы проверить, нет ли event.state . Если это так, мы возвращаемся к нашей первоначальной форме.

  $ (window) .bind ("popstate", function (evt) {
               if (event.state) {
                   url = event.state.url;
                   $ .get (url, function (data) {
                       $ ( "# Contentarea") HTML ( "").
                       $ ( "# Contentarea") HTML (шаблон (данные)).
                   }, "JSON");
                backtostart = false;
               } еще {
                if (! backtostart) {
                   // вернуть содержимое к оригиналу
                   backtostart = true;
                       $ ( "# Contentarea") HTML ( "").
                       $ ( "# Contentarea") HTML (оригинал).
                } еще {
                  // сохранить исходный контент для последующего извлечения
                  original = $ ("# contentarea"). html ();
                     backtostart = false;
                }
             }
           }); 

Наконец, мы добавляем наш обработчик события click ко всем соответствующим ссылкам. В нашем случае мы просто используем ссылки в списке, но на практике вы можете сделать это со всем диапазоном ссылок на HREF атрибутов class или HREF .

  $ ("ul # storylist li a"). bind ("click", story_link_handler); 

Остальная часть страницы — это структура страницы и фактический контент, который был запрошен — в данном случае URL /frankenstein .

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

URL обновляется с помощью pushState() что означает, что пользователь все еще может делиться URL с помощью намерений или копировать и вставлять, и этот URL будет работать правильно для всех, кому он предоставлен. Вы также получаете преимущество в том, что каждый документ по-прежнему существует должным образом — это означает, что поисковые системы могут по-прежнему правильно индексировать ваш сайт, если это необходимо.

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

Где этот метод работает особенно хорошо, это сценарий «бесконечной прокрутки», такой как поток контента или очень длинная статья. Тип содержимого практически не изменяется (или только в очень определенном порядке) — этот метод делает для «содержимого страницы» в целом то же, что и метод ленивой загрузки для изображений на странице. Если вы потратили время на разбиение контента на части, это может быть особенно эффективно, поскольку это означает, что вы можете избежать попадания пользователя на «страницу 2», даже если поисковые системы будут следовать за вами.

Скачать файлы кода, используемые в этой статье

Окунитесь в мир адаптивного веб-дизайна в новой книге Эндрю с Крейгом Шарки: Jump Start Responsive Web Design .