В предыдущей статье мы рассмотрели, как написать собственный модуль для 1С-Битрикс. Сегодня я решил продолжить эту тему и переключиться на компонент. Это логически завершенная часть системы и хорошо подходящая для реализации AJAX подгрузки контента или, как по-другому называют, AJAX навигации.
Перед тем, как начать, предлагаю обратиться к маркету Битрикс и узнать какие решения этой задачи уже есть. Разнообразия тут маловато и все варианты платные:
Попробовав их, я наткнулся на ситуацию, что некоторые просто не работают, а другие неудобны. Как по мне: упаковать AJAX навигацию в модуль не лучший вариант, а компонент - как раз то, что нужно.
Структура компонента
Как уже принято, разрабатываемый компонент помещаем в папку local, что позволит отделить дополнительный функционал, и уменьшить захламлённость сайта. Сама же структура будет выглядеть так:
- falbar – область видимости нашего компонента в системе, внутри её лежит уже, непосредственно, наш компонент ajax.pagenavigation;
- Далее мы видим две стандартных папки с языковыми данными, шаблонами компонента;
- И в завершение три стандартных файла: class.php (автоматически подключаемый файл при вызове компонента),.parameters.php (параметры компонента),.description.php (описание компонента в системе).
В папке lang будут находиться два варианта для русскоязычного и англоязычного определения. В дальнейшем в статье примеры будут только для русскоязычного варианта.
В шаблонах у нас будет только один (по умолчанию) вариант. Для нашей задумки потребуется реализовать простенькую верстку со стилями, а также написать JavaScript код, который и будет осуществлять подгрузку контента.
Первые шаги перед написанием компонента
Перед тем, как начать писать компонент, необходимо определиться с его настройками. Для начальной реализации их будет не много. Нам понадобится:
- Для получения количества элементов, нам потребуется знать в котором инфоблоке будет вызван компонент;
- Так же нам потребуется класс или индификатор обертки, в которой будут находиться наши новости, товары или другие элементы;
- Ещё потребуется знать класс или индификатор для обёрток навигации и самого элемента.
По настройкам всё. Теперь можно описать саму логику решения: после того, как мы добавим наш компонент (AJAX навигация), первым делом спрячем стандартную Битрикс навигацию. Далее мы отобразим кнопку при нажатии на которую, будет подгружаться контент и добавляться к существующему. Также учтем страницы пагинации, чтобы пользователь не мог на них зайти, установим 404 ридирект. Звучит всё просто – приступим!
Работаем над файлом описания компонента
Для того, чтобы наша навигация появилась в редакторе нам нужно заполнить файл .description.php. Тут есть один момент, который я заметил: при сбросе кэша в редакторе результата мы не увидим, его нужно сбрасывать в административной части. Хотя может это только у меня так.
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
use Bitrix\Main\Localization\Loc;
Loc::loadMessages(__FILE__);
$arComponentDescription = array(
"NAME" => Loc::getMessage("FALBAR_AJAX_PAGENAVIGATION_DESC_NAME"),
"DESCRIPTION" => Loc::getMessage("FALBAR_AJAX_PAGENAVIGATION_DESC_DESC"),
"PATH" => array(
"ID" => Loc::getMessage("FALBAR_AJAX_PAGENAVIGATION_DESC_ID")
)
);
Тут у нас стандартная структура описания - все текста вынесены в соответствующие lang-файлы:
$MESS["FALBAR_AJAX_PAGENAVIGATION_DESC_NAME"] = "AJAX навигация";
$MESS["FALBAR_AJAX_PAGENAVIGATION_DESC_DESC"] = "AJAX навигация.";
$MESS["FALBAR_AJAX_PAGENAVIGATION_DESC_ID"] = "Фалбар";
В результате, когда вы зайдёте в редактор страницы, будет видна такая картина:
Значит всё правильно и можно продолжать работать.
Файл параметров компонента
Как выше было указано нам потребуется ряд параметров. В данном разделе в самом начале нам нужно получить список всех инфоблоков:
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Loader;
Loc::loadMessages(__FILE__);
Loader::includeModule("iblock");
$iblocks = CIBlock::GetList(
array(
"SORT" => "ASC"
),
array(
"ACTIVE" => "Y"
)
);
$iblock_values = array();
while($iblock = $iblocks->Fetch()){
$iblock_values[$iblock["ID"]] = "[".$iblock["ID"]."] ".$iblock["NAME"];
}
Это легко реализуется стандартными методами API Битрикс, что видно выше в коде. Далее сформируем массив с параметрами нашего компонента:
$arComponentParameters = array(
"PARAMETERS" => array(
"IBLOCK" => array(
"NAME" => Loc::getMessage("FALBAR_AJAX_PAGENAVIGATION_PARAM_IBLOCK"),
"TYPE" => "LIST",
"VALUES" => $iblock_values
),
"SELECTOR_WRAPPER_NAVIGATION" => array(
"NAME" => Loc::getMessage("FALBAR_AJAX_PAGENAVIGATION_PARAM_NAVIGATION"),
"TYPE" => "STRING"
),
"SELECTOR_WRAPPER_CONTENT" => array(
"NAME" => Loc::getMessage("FALBAR_AJAX_PAGENAVIGATION_PARAM_CONTENT"),
"TYPE" => "STRING"
),
"SELECTOR_ELEMENT" => array(
"NAME" => Loc::getMessage("FALBAR_AJAX_PAGENAVIGATION_PARAM_ELEMENT"),
"TYPE" => "STRING"
)
)
);
Как видно вся структура этого массива однотипна, а о том, что она может содержать – хорошо описано в официальной документации Битрикс. Хотя лучший пример для изучения - это уже написанные компоненты. Добавим в соответствующие языковые файлы наши названия:
$MESS["FALBAR_AJAX_PAGENAVIGATION_PARAM_IBLOCK"] = "Инфоблок";
$MESS["FALBAR_AJAX_PAGENAVIGATION_PARAM_NAVIGATION"] = "Селектор обертки навигации";
$MESS["FALBAR_AJAX_PAGENAVIGATION_PARAM_CONTENT"] = "Селектор обертки контента";
$MESS["FALBAR_AJAX_PAGENAVIGATION_PARAM_ELEMENT"] = "Селектор элемента";
Осталось увидеть результат:
Перед тем, как переходить к следующей части статьи, нам нужно заполнить параметры и разместить компонент на странице. Для примера добавим его на страницу продукции стандартного Битрикс шаблона:
И настроим следующим образам:
Пишем логику компонента
В новом ядре Битрикс D7 логика компонента располагается в файле class.php. Что нам нужно? Первое - подключить шаблон. Далее получить параметры и их обработать, а в конце сформировать массив $arParams. Так же в своей работе мы будем использовать библиотеку jQuery, следовательно мы его подключим. Приступим!
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
use Bitrix\Main\EventManager;
use Bitrix\Main\Loader;
use Bitrix\Main\Context;
Loader::includeModule("iblock");
class AjaxPagenavigation extends CBitrixComponent{
// Остальной код пишем тут
}
В начале файла подключим нужные нам классы API, и создадим класс наследник AjaxPagenavigation от CBitrixComponent. Двигаемся дальше и переопределим в нем метод executeComponent(). В нем мы проверим на наличие в адресной строке параметра PAGEN и, если он есть, перенаправим пользователя на 404 страницу. Также обратимся к приватному методу initEvents(), где создадим событие перед загрузкой страницы (в нем подключим jQuery библиотеку). В конце подключим шаблон компонента:
public function executeComponent(){
$request = Context::getCurrent()->getRequest();
if(!$request->isAjaxRequest()){
$server = Context::getCurrent()->getServer();
if(strpos($server->getRequestUri(), "PAGEN_") !== false){
LocalRedirect("/404.php", "404 Not Found");
}
}
$this->initEvents();
$this->includeComponentTemplate();
return false;
}
private function initEvents(){
EventManager::getInstance()->addEventHandler(
"main",
"OnBeforeEndBufferContent",
function(){
CJSCore::Init(
array(
"jquery"
)
);
}
);
return false;
}
Осталось разобраться с параметрами:
public function onPrepareComponentParams($params = array()){
if($params){
$params["COUNT"] = CIBlock::GetElementCount($params["IBLOCK"]);
unset($params["IBLOCK"]);
unset($params["CACHE_TYPE"]);
$params["PARAMS"] = json_encode($params);
unset($params["SELECTOR_ELEMENT"]);
unset($params["SELECTOR_WRAPPER_CONTENT"]);
unset($params["SELECTOR_WRAPPER_NAVIGATION"]);
unset($params["COUNT"]);
return $params;
}
return false;
}
В методе onPrepareComponentParams() наша задача сформировать элемент PARAMS массива $arParams. В себе он сдержит заполненные пользователем настройки, а также полученное число записей в инфоблоке. Хорошим тоном будет удалить из массива параметры, которые мы не используем.
Шаблон компонента по умолчанию
Закончив с основной частью, нам нужно сформировать шаблон. Он будет максимально простым:
<?
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
use Bitrix\Main\Localization\Loc;
Loc::loadMessages(__FILE__);
?>
<div id="falbar-ajax-pagenavigation-wrapper" data-params="<? echo($arParams["PARAMS"]); ?>">
<span id="falbar-ajax-pagenavigation-button">
<? echo(Loc::getMessage("FALBAR_AJAX_PAGENAVIGATION_TEMP_BUTTON")); ?>
</span>
</div>
Сразу же заполним lang-файлы:
$MESS["FALBAR_AJAX_PAGENAVIGATION_TEMP_BUTTON"] = "Ещё";
И укажем в завершении CSS стили:
div#falbar-ajax-pagenavigation-wrapper{
text-align: center;
padding: 20px;
}
span#falbar-ajax-pagenavigation-button{
cursor: pointer;
font-weight: bold;
opacity: 0.9;
}
span#falbar-ajax-pagenavigation-button:hover{
opacity: 1;
}
В результате всей этой магии мы получаем кнопку на странице, с которой уже и будем работать в JS файле:
Последний этап разработки компонента JavaScript
Вот мы и подобрались к финальной части нашей сегодняшней темы – AJAX навигация. Весь код будет исполняться после загрузки страницы:
$(function(){
// Наша подгрузка
});
Найдем кнопку на странице и наши параметры:
var wrapper = $("#falbar-ajax-pagenavigation-wrapper"),
button = $("#falbar-ajax-pagenavigation-button");
if(wrapper.length){
var params = wrapper.data("params");
if(params){
// Ещё глубже
};
};
Далее получим все необходимые настройки:
var navigation = $(params.SELECTOR_WRAPPER_NAVIGATION),
pagenStr = navigation.find("a").attr("href"),
pagenIndex = pagenStr.indexOf("PAGEN_") + 1,
element = params.SELECTOR_ELEMENT,
content = $(params.SELECTOR_WRAPPER_CONTENT),
elementCount = params.COUNT;
После чего спрячем стандартную навигацию Битрикс:
navigation.hide();
И в зависимости от числа записей, опишем действия после нажатия на кнопку «Ещё»:
if(pagenIndex){
pagenStr = pagenStr.substring(pagenIndex - 1, pagenIndex + 7);
wrapper.attr("data-page", 1);
button.on("click", function(){
var pageCurrent = parseInt(wrapper.attr("data-page")),
elementCountCurrent = $(element).length;
if(elementCount != elementCountCurrent){
++pageCurrent;
BX.showWait();
$(this).hide();
$.ajax({
url: location.origin + location.pathname + "index.php?" + pagenStr + pageCurrent,
success: function(data){
content.append(
$(data).find(element)
);
wrapper.attr("data-page", pageCurrent);
BX.closeWait();
if(elementCount != $(element).length){
button.show();
};
}
});
};
return false;
});
};
В выше указанном коде, важно пояснить: сформировав путь следующей страницы мы получаем её целиком и уже средствами jQuery достаем необходимые записи.
В результате у нас получился хороший компонент, который позволит добавить AJAX пагинацию за несколько минут на любой странице. Если вы проделали все этапы вместе со мной, то уже смогли в этом убедиться.