Поддержка журнала и кнопки "Назад"
Илайджа Менор (Elijah Manor) | 13 мая 2010 г. Разработка интерактивных веб-сайтов замечательна для удобства использования, но одна общая проблема современных веб-сайтов — недостаточная поддержка кнопок "Журнал" и "Назад" при использовании библиотек JavaScript и технологии AJAX. Пользователи предполагают, что после нажатия кнопки "Назад" вернутся в предыдущее состояние веб-страницы, однако в типичном приложении с использованием технологии AJAX нажатие кнопки "Назад" может привести пользователя в состояние, которое было несколько шагов назад. Это не только запутывает пользователей; весьма вероятно, что они подумают, что в данном программном обеспечении имеется ошибка, и будут менее удовлетворены взаимодействием в целом. Недостаток такой поддержки частично объясняется тем, что разработчики должны добавлять дополнительную логику для перехвата кнопки "Назад" и соответствующей реакции на ее нажатие. Поскольку веб-браузер не знает, что за кулисами выполняются операции с моделью DOM, он не отслеживает их. Для устранения этой проблемы создано несколько проектов, таких как разработанный Микаге Саватари (Mikage Sawatari) подключаемый модуль jQuery History, разработанный компанией Asual подключаемый модуль jQuery Addres, разработанный Джимом Палмером (Jim Palmer) подключаемый модуль jQuery jHistory и разработанный Беном Алманом (Ben Alman) подключаемый модуль jQuery BBQ. Все эти библиотеки предоставляют технологии для поддержки кнопки "Назад" и разрешают ссылки с возможностью создания закладок, но некоторые из них оказываются лучше, если учесть простоту использования, поддержку в разных браузерах и активную разработку. Подключаемый модуль jQuery BBQ В этой статье я сосредоточусь на подключаемом модуле jQuery BBQ, написанном Беном Алманом (Ben Alman). Имя подключаемого модуля, BBQ, представляет сокращение слов Back Button (кнопка "Назад") и Query library (библиотека запросов). С этого момента я буду называть подключаемый модуль jQuery BBQ просто BBQ. Бен приложил много усилий, чтобы его подключаемый модуль мог поддерживаться в разных браузерах. По его словам, этот подключаемый модуль был проверен с jQuery 1.3.2, 1.4.1, 1.4.2 в Internet Explorer 6–8, Firefox 2–3.7, Safari 3–4, Chrome 4–5, Opera 9.6–10.1 и Mobile Safari 3.1.1. Один из многих моментов, которые я принимаю во внимание, прежде чем потратить время и рискнуть добавить библиотеку в свой проект, это активное участие автора. Я хочу знать, что будут исправляться ошибки и будут вноситься улучшения. Меньше всего мне бы хотелось, чтобы библиотека оказалась застоявшейся и мешала выполнению обновления до новой версии jQuery. Бен прилагает сознательные усилия, чтобы сохранить актуальность BBQ для последней версии jQuery, предоставляя полную документацию по своему подключаемому модулю, и написал набор из более трехсот модульных тестов. Вы можете проверить развитие его проекта на странице проекта GitHub. Навигация с помощью хэша URL-адреса Прежде чем углубиться в детали BBQ, давайте кратко рассмотрим текущее состояние браузера и идентификаторы фрагментов. В настоящее время браузеры поддерживают синтаксис #hash в URL-адресе для переходов вверх и вниз на одной и той же странице. Например, я уверен, что вы иногда делали что-то подобное (вы можете просматривать, выполнять и изменять этот пример кода с сайта jsFiddle):
Если вы нажмете тег привязки "Go To Top", то страница перейдет в расположение элемента с атрибутом id элемента "top" (или именованной привязки с атрибутом name элемента "top"). Происходит не только отправка вас в фрагмент "Top of Page", но также и URL-адрес дополняется идентификатором фрагмента "#top". Если создать закладку этой страницы и вернуться на нее позже, то вы окажетесь в том же самом положении. С помощью этого синтаксиса разработчики могут помечать URL-адреса специальными данными и затем отвечать с использованием JavaScript, что собственно и делается в нашем первом примере. Событие hashchange jQuery Внутри BBQ использует событие hashchange HTML5 для ответа, когда изменяется идентификатор фрагмента (#hash) в URL-адресе. Бен предоставляет поддержку hashchange в разных браузерах внутри его события hashchange jQuery. В настоящее время только браузеры Internet Explorer 8, Firefox 3.6 и Chrome 5 предоставляют встроенную поддержку. Бен использовал некоторые специальные приемы, чтобы добиться работы события hashchange в других браузерах и в более старых версиях, и если вас это заинтересовало, вы можете узнать об этом более подробно на его веб-сайте. Пример использования события hashchange В зависимости от приложения, можно выйти из положения с помощью только события hashchange jQuery, без использования всего подключаемого модуля BBQ. Если в приложении уже используется #hash для обслуживания состояния внутри веб-страницы, то можно воспользоваться самим по себе событием hashchange jQuery. В последнем примере я покажу, как использовать весь подключаемый модуль BBQ, и опишу, когда это необходимо делать. Я разместил вместе простой пример вкладки jQuery (см. рисунок 1), в котором используются значения #hash в атрибуте href каждого элемента привязки вкладки.
В этом примере я использовал стандартную методику #hash для обслуживания состояния в браузере, подобно показанному выше примеру "Back To Top". Мне не потребовалось делать что-то специальное, чтобы получить значение #hash в URL-адресе. Браузер делает это сам, поскольку он распознает эту методику. Я использовал событие hashchange не для перехода в другое место страницы, а для ответа на изменение. Как можно было ожидать, я подключил обработчик событий к элементу привязки во вкладке, и после нажатия вкладки я соответствующим образом обновляю вкладки. В этом примере есть два особых отличающихся момента, которые следует отметить. Один — это наличие $(window).bind("hashchange", function() {});. Это ключевая точка входа для события hashchange. Мы прослушиваем любое изменение location.hash и отвечаем на него в обработчике событий. Это событие захватывает location.hash, который является href в атрибуте href привязки вкладки. location.hash соответствует атрибуту id содержимого div вкладки. Если #hash отсутствует, то по умолчанию устанавливается первая вкладка. Второе, что следует отметить, это оператор $(window).trigger('hashchange'); в конце примера кода. Единственная причина для этого события-триггера — загрузка начальной страницы. Если кто-либо переходит на страницу с #hash в качестве части URL-адреса, требуется принять на обработку этот запрос и отобразить соответствующую вкладку, соответствующую этому #hash. Общие сведения об API подключаемого модуля jQuery BBQ Прежде чем показать другой пример кода, давайте еще немного изучим подключаемый модуль jQuery BBQ и выделим часть его API. При начале использования подключаемого модуля jQuery BBQ необходимо знать три основных метода. Эти три основных действия — помещение текущего "состояния" (думайте о нем как о снимке момента времени) страницы, получение этого состояния снова, чтобы можно было на него ответить, и удаление состояния, когда оно не используется. jQuery.bbq.pushState Добавляет текущее состояние в журнал браузера. Обновляет location.hash. Вызывает событие hashchange. jQuery.bbq.getState Извлекает текущее состояние из журнала браузера. Возвращает либо конкретный ключ из location.hash, либо полное состояние. jQuery.bbq.removeState Удаляет один или несколько ключей из текущего журнала браузера. Создает новое состояние путем обновления location.hash. Вызывает событие hashchange. Пример использования подключаемого модуля jQuery BBQ Давайте рассмотрим немного другой подход из предыдущего примера, и на этот раз атрибут href не будет использоваться для включения значения #hash. Поскольку мы не используем значения #hash в качестве части нашего атрибута href привязки, нам необходимо обработать помещение значений #hash в URL-адрес, получение их и удаление вручную. Вид и логика у этого примера (см. рисунок 2) будут такими же, как и у предыдущего, но в этом примере закулисно используется подключаемый модуль BBQ для управления историческим состоянием.
Предыдущий фрагмент HTML предоставляет метаданные в атрибуте class вкладки для сопоставления id содержимого div, которое должно отображаться. Эти метаданные можно извлечь с помощью подключаемого модуля jQuery Metadata. Для тех, кто не знаком с подключаемым модулем jQuery Metadata, он предоставляет способ внедрения сведений JSON в атрибут и извлечения десериализованной версии во время выполнения.
На этот раз вместо вызова обоими обработчиками событий click вкладки и hashchange окна метода updateTabs я удалил его из обработчика событий вкладки, и теперь он только помещает ее состояние в подключаемый модуль jQuery BBQ. Это позволяет обработчику событий hashchange обрабатывать логику, чтобы соответствующим образом обновлять пользовательский интерфейс. Обработчику событий click вкладки необходимо поместить ее состояние в подключаемый модуль jQuery BBQ, поскольку мы не используем ту методику #hash, которую понимает браузер. (См. пример "Back To Top" в начале этой статьи.) За кулисами подключаемый модуль jQuery BBQ обновляет URL-адрес, так что браузер понимает, что вы обновили состояние страницы, и сохраняет эти сведения в журнале. Расширенный пример подключаемого модуля jQuery BBQ Показанные в последних двух примерах фрагменты кода вкладок — не самые сложные сценарии в мире. Давайте рассмотрим что-нибудь посложнее. Теперь мы собираемся построить сортируемый список, который можно переупорядочивать, перетаскивая элементы вверх или вниз. Если дважды щелкнуть один из элементов, появляется диалоговое окно, показывающее сведения, полученные с помощью технологии AJAX. После некоторого взаимодействия пользователя с приложением (переупорядочивания элементов, открытия или закрытия диалоговых окон и т. п.) задача состоит в том, чтобы вернуть состояние до действия при нажатии в браузере кнопки "Назад". Давайте сначала взглянем на HTML, с которым работаем. У нас есть неупорядоченный список с рядом элементов списка, каждый из которых содержит имя пользователя в Твиттере и число записей в Твиттере для извлечения. Также имеется элемент divdialog, в котором отображается результат запроса AJAX. (См. рисунок 3.)
При упорядочивании элемента списка код создает уникальный ключ (число миллисекунд, прошедших с полночи 1 января 1970 г.) и использует его для кэширования порядка элементов списка в массиве. Затем этот уникальный ключ последовательности помещается в подключаемый модуль jQuery BBQ. Аналогично, когда выполняется двойной щелчок элемента списка, id элемента помещается в BBQ. Затем эти сведения используются для открытия диалогового окна. Также следует упомянуть, что при щелчке диалогового окна его сведения удаляются из BBQ. (Вы можете просматривать, выполнять и изменять следующий пример кода с jsFiddle.)
Опять код слегка изменен по сравнению с тем, что могло бы быть написано без поддержки кнопки "Назад". В этом случае скорее всего пришлось бы поместить логику в обработчики событий. Вместо этого я использовал их расположения, чтобы поместить их состояние в BBQ, и таким образом обработчик событий hashchange может обрабатывать эту логику. В обработчике событий hashchange мы извлекаем id элемента списка из BBQ. Если id существует, значит должно быть отображено диалоговое окно. К элементу списка подключаются метаданные со сведениями Твиттера, которые используются контентом AJAX для отображения в диалоговом окне. Обработчик событий hashchange также захватывает идентификатор последовательности, который является ключом для кэшированного списка упорядоченных элементов из конкретного состояния (момента времени). Затем код переупорядочивает этот неупорядоченный список с помощью написанного мной небольшого подключаемого модуля jQuery. Более глубокий обзор документации Предыдущие примеры в этой статье так или иначе связаны с тремя методами pushState, getState и removeState. Однако подключаемый модуль jQuery BBQ предоставляет гораздо больше функций, которые модно использовать в приложениях. Многие из этих методов используются закулисно при вызове трех методов состояния. Например, возможно вы знаете о методе jQuery.param, который предоставляется корневой библиотекой jQuery. Этот метод сериализует массив или объект в формат, подходящий для строки запроса URL-адреса. Однако корневая библиотека jQuery не предоставляет метод для десериализации строки запроса URL-адреса. Здесь вступает в действие BBQ. BBQ предоставляет метод jQuery.deparam для десериализации строки запроса URL-адреса в объект. Кроме того, Бен предоставляет методы jQuery.deparam.querystring и jQuery.deparam.fragment, которые выполняют десериализацию определенных частей URL-адреса. Как можно понять, эти методы жизненно важны для внутренней работы подключаемого модуля, но особо впечатляет то, что они также подходят и для использования вами! Если вас заинтересовали эти и другие методы, см. расширенную документацию по BBQ и сопутствующие примеры. Кто такой Бен Алман (Ben Alman)? Кроме подключаемого модуля jQuery BBB, Бен Алман принимал участие во многих других полезных проектах, включая следующие. jQuery equalizeBottoms — позволяет устанавливать одинаковую высоту нескольких элементов. jQuery outside events — позволяет вызывать событие, когда пользователь осуществляет взаимодействие вне конкретного элемента. jQuery replaceText — позволяет заменять текст в выделенной области, не путая все элементы и значения атрибутов. jQuery resize event — позволяет выполнять привязку к событию изменения размера конкретного элемента модели DOM. jQuery throttle / debounce — позволяет ограничить методы по времени. Это может быть полезно, если вы не хотите бомбардировать сервер тоннами запросов. Бен не только разработал много высококачественных проектов, но также принимал участие во внесении существенных изменений в корневую библиотеку jQuery. Если вы серьезно заинтересовались jQuery, то можете разобраться, посетив Бена Алмана в его блоге, Твиттере или на сайте GitHub. Заключение В сегодняшних решениях на основе JavaScript и технологии AJAX с высокой степенью интерактивности не следует терять функциональность, которую использует и ожидает пользователь, такую как поддержка журнала и кнопки "Назад", а также закладки. С помощью подключаемого модуля jQuery BBQ можно предоставить эти функции пользователям, не ставя под угрозу высокий уровень их удовлетворенности. Если вы заинтересовались продолжением изучения jQuery, я рекомендую посетить меня в Твиттере, чтобы получить свежий набор ссылок jQuery, а также посмотреть в моем блоге ежедневный обзор технических записей, содержащий множество ссылок jQuery, которые помогут в процессе изучения. |