Drupal 7 и PJAX, разработка сайта, нюансы

Категория: Drupal
Дата публикации: 15 января, 2016 - 20:19
Последнее изменение: 15 января, 2016 - 20:25

В одном из проектов на Drupal 7 заказчик потребовал чтобы на сайте был установлен плеер и проигрывалась фоновая музыка. Разумеется, во время переходов на другие страницы никаких прерываний быть не должно. Плеер был реализован на библиотеке jplayer (http://jplayer.org/).

Оставалось самое "простое" - сделать так, чтобы при переходе по страницам музыка не прерывалась.
Решение - добавить функцию ajax загрузки страниц, но с таким расчетом, чтобы:

  • все страницы были доступны по прямым ссылкам
  • URL в браузерной строке менялся при переходе по ссылкам
  • сайт индексировался без каких-либо проблем для поисковых систем
  • не пришлось переделывать весь сайт, так как "хотелка" в виде этого плеера поступила уже намного позже начала работы над сайтом

jquery-pjax позволяет любой сайт переделать "под ajax", однако в процессе разработки возникает масса нюансов, решения которых я постараюсь рассказать в данном посте.
Надо отметить, что на Drupal.org есть несколько модулей для настройки pjax, но после тестов от этих модулей я отказался, заставить их работать не удалось.

1. Подключение pjax ничем не отличается от добавления любого другого js в тему оформления. В .info-файл темы добавляем, после чего не забываем сбросить кеш:

scripts[] = js/jquery.pjax.js

2. Создаем и подключаем новый js-файл к теме оформления. В нем мы и будет все настраивать и конфигурировать.
Для инициализации pjax нужно указать:

- какой фрагмент (div ID) страницы содержит контент, именно эта часть страницы будет подгружаться, а остальные элементы страницы загрузятся всего один раз при первой загрузке страницы.
- по клику на какие элементы должен срабатывать pjax и загружать контент. В моем случае это все ссылки из меню и все ссылки в контенте.

Получается примерно так:

(function ($, Drupal, window, document, undefined) {

Drupal.behaviors.test_pjax = {
  attach: function(context, settings) {

//pjax
$(document).pjax('#page a, #footer a', '#content', { fragment: '#content' });
$.pjax.defaults.timeout = 7000;
$.pjax.defaults.maxCacheLength = 0;

  }
};

$.pjax.defaults.timeout и $.pjax.defaults.maxCacheLength - это увеличение таймаута и отключение кеша pjax. Это сэкономит много часов (без этой строчки, например, при возврате на страницу через кнопку браузера "назад" на странице переставала работать галерея-карусель) :).

3. Основная сложность при реализации ajax в том, что при каждой загрузке новой страницы нужно заново инициализировать любой js-код, функции, иначе они просто не заработают. Решение следующее: создание своей собственной функции (в моем случае это myInitFunction(); ), которая будет срабатывать каждый раз ПОСЛЕ окончания запроса pjax.

(function ($, Drupal, window, document, undefined) {

Drupal.behaviors.test_pjax = {
  attach: function(context, settings) {

//pjax
$(document).pjax('#page a, #footer a', '#content', { fragment: '#content' });
$.pjax.defaults.timeout = 7000;
$.pjax.defaults.maxCacheLength = 0;

//pjax after ready
$(document).on("ready pjax:end", function() {

myInitFunction();

});

  }
};

4. Добавляем нашу функцию myInitFunction() в js-файл

(function ($, Drupal, window, document, undefined) {

Drupal.behaviors.test_pjax = {
  attach: function(context, settings) {

// reinit all function after pjax end
function myInitFunction() {

}

//pjax
$(document).pjax('#page a, #footer a', '#content', { fragment: '#content' });
$.pjax.defaults.timeout = 7000;
$.pjax.defaults.maxCacheLength = 0;

//pjax after ready
$(document).on("ready pjax:end", function() {

myInitFunction();

});

  }
};

Теперь весь js-код, за некоторым исключением, будет располагаться внутри функции. Исключение у меня составили - jPlayer и fancybox. Их я вынес за пределы функции.

5. В моем случае на сайте было несколько штук каруселей, всплывающая форма, модальные окна для просмотра картинок... Так что очень активно я использовал привязку по контексту, чтобы js не выполнялся при каждом ajax-запросе (в данном случае имеется ввиду ajax от Drupal).

(function ($, Drupal, window, document, undefined) {

Drupal.behaviors.test_pjax = {
  attach: function(context, settings) {

// reinit all function after pjax end
function myInitFunction() {

//owl-demo
$("#owl-demo", context).once( function () {

$("#owl-demo").owlCarousel({

items : 3,
itemsDesktop : [1199,3],
itemsDesktopSmall : [979,3],
itemsTablet: [979,3],
itemsMobile : [479,2],
rewindNav:true,
pagination:false,
loop: true,
slideSpeed : 1000,
autoPlay:5000,
  });
 
})

}

//pjax
$(document).pjax('#page a, #footer a', '#content', { fragment: '#content' });
$.pjax.defaults.timeout = 7000;
$.pjax.defaults.maxCacheLength = 0;

//pjax after ready
$(document).on("ready pjax:end", function() {

myInitFunction();

});

  }
};

6. Проблема активных ссылок. Так как полная перезагрузка страницы с pjax не происходит, то к ссылкам, например, в меню, не добавляется класс "active". Это я решал вот такими костылями:

$("ul.menu a").click(function(){
$('.active').removeClass('active');
$(this).addClass('active');
})

$("#logo img").click(function(){
$('.active').removeClass('active');
$('#block-menu li.is-leaf.first a').addClass('active');
});

Первый блок кода удаляет текущий класс "active" (если он был) и добавляет его на ту ссылку, по которой был сделан клик.
Второй блок кода делает все точно тоже самое, но по клику на логотип и добавляет активный класс на пункт меню "главная".

Используемые материалы:
http://stackoverflow.com/questions/10713546/how-to-run-jquery-before-and...
https://github.com/defunkt/jquery-pjax/issues/469
https://github.com/defunkt/jquery-pjax/issues/235
https://github.com/defunkt/jquery-pjax/issues/166
https://github.com/defunkt/jquery-pjax/issues/152
http://stackoverflow.com/questions/30884350/button-not-working-on-pjax-r...

Добавить комментарий