По шагам:
- Создадим шаблон компонента постраничной навигации (bitrix:system.pagenavigation);
- Адаптируем шаблон компонента списка новостей (bitrix:news.list);
- Разместим на странице и настроим компонент (bitrix:news.list).
1. Создание шаблона постраничной навигации
Я покажу как сделать это вручную, но вы можете просто скопировать один из стандартных шаблонов и заменить в нем код на мой.
Для начала создадим раздел "system.pagenavigation" в шаблоне сайта: /bitrix/templates/[ваш шаблон]/components/bitrix/ или /local/templates/[ваш шаблон]/components/bitrix/. Если раздел уже существует (как в моём случае), новый создавать не надо:)
В нем создадим подраздел с названием нашего шаблона. Назовем его "show_more" (я буду использовать phpStorm, но те же действия можно проделатьс помощью других редакторов или админки Битрикс).
Каждый шаблон компонента должен содержать файл template.php, в нем будет храниться оформление. Также для реализации динамической подгрузки нам потребуются файлы script.js и style.css, где мы пропишем соответственно скрипт и стили.
Первым делом возьмемся за template:
<?
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
$this->createFrame()->begin("Загрузка навигации");
?>
<?if($arResult["NavPageCount"] > 1):?>
<?if ($arResult["NavPageNomer"]+1 <= $arResult["nEndPage"]):?>
<?
$plus = $arResult["NavPageNomer"]+1;
$url = $arResult["sUrlPathParams"] . "PAGEN_".$arResult["NavNum"]."=".$plus;
?>
<div class="load_more" data-url="<?=$url?>">
Показать еще
</div>
<?else:?>
<div class="load_more">
Загружено все
</div>
<?endif?>
<?endif?>
На первые две строки не обращаем внимание, в рамках этой статьи мы их рассматривать не будем.Дальше два условия: кнопка загрузки будет показываться когда страниц больше 1 и когда есть следующая страница (текущая + 1).
Кнопка будет представлять собой div с параметром data-url - адресом следующей станицы для подгрузки, классом load_more и надписью "Показать еще".
Читайте также: 7 смертных грехов разработки на 1С-Битрикс.
Если страницы постраничной навигации кончились - покажем надпись "Загружено все".
Следующий файл стилей. В нем будет оформление кнопки. Для примера я использовал простейшее оформление:
.load_more {
margin: 10px;
padding: 10px;
border: 1px solid #ddd;
cursor: pointer;
text-align: center;
}
В сумме со стилями моего сайта, кнопка будет выглядеть как в примере. Вы же оформите её как вам нравится:)Теперь самое главное - скрипт:
$(document).ready(function(){
$(document).on('click', '.load_more', function(){
var targetContainer = $('.news-list'), // Контейнер, в котором хранятся элементы
url = $('.load_more').attr('data-url'); // URL, из которого будем брать элементы
if (url !== undefined) {
$.ajax({
type: 'GET',
url: url,
dataType: 'html',
success: function(data){
// Удаляем старую навигацию
$('.load_more').remove();
var elements = $(data).find('.news-item'), // Ищем элементы
pagination = $(data).find('.load_more');// Ищем навигацию
targetContainer.append(elements); // Добавляем посты в конец контейнера
targetContainer.append(pagination); // добавляем навигацию следом
}
})
}
});
});
Как это работает: после нажатия на кнопку (div) срабатывает событие, отсылающее ajax запрос к указанному в кнопке адресу (атрибут data-id). Мы удаляем старую навигацию (класс .load_more), чтоб она не дублировалась. В полученных данных ищем элементы (в нашем случае класс .news-item, о нем чуть ниже) и уже известную нам навигацию (.load_more).Последним этапом работы скрипта, в контейнер .news-list (о нем тоже ниже) добавляем полученные элементы и навигацию.
2. Шаблон компонента списка новостей
Создадим папку шаблона компонента (/local/templates/[ваш шаблон]/components/bitrix/news.list/show_more_news/, либо /bitrix/templates/[ваш шаблон]/components/bitrix/news.list/show_more_news/).Шаблон будет состоять всего из одного файла template.php:
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
$this->setFrameMode(true);
?>
<div class="news-list">
<?foreach($arResult["ITEMS"] as $arItem):?>
<?
$this->AddEditAction($arItem['ID'], $arItem['EDIT_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_EDIT"));
$this->AddDeleteAction($arItem['ID'], $arItem['DELETE_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_DELETE"), array("CONFIRM" => GetMessage('CT_BNL_ELEMENT_DELETE_CONFIRM')));
?>
<div id="<?=$this->GetEditAreaId($arItem['ID']);?>" class="news-item">
<a href="<?=$arItem["DETAIL_PAGE_URL"]?>">
<h2><?=$arItem["NAME"]?></h2>
</a>
<?=CFile::ShowImage($arItem['PREVIEW_PICTURE'])?>
<?=$arItem['PREVIEW_TEXT']?>
</div>
<?endforeach;?>
</div>
<?=$arResult['NAV_STRING']?>
Вообще, оформление вы можете использовать какое угодно. Важная деталь: все элементы должны быть обёрнуты в блок с классомnews-list, а каждый элемент иметь классnews-item (как в скрипте из второго пункта).
3. Размещение на странице и настройка компонента
На нужной странице размещаем компонент bitrix:news.list и настраиваем на необходимый инфоблок.В качестве шаблона компонента выбираем show_more_news (если вы все сделали правильно он должен появиться в списке), а в качестве шаблона постраничной навигации - show_more
И указываем нужное количество новостей на странице. Именно столько элементов будет подгружаться после нажатия на кнопку.
Еще раз пример того, что у меня получилось: gif (3.17 Mb).
Дмитрий, спасибо! Работает ваше решение.
А как вывести элементы только из подраздела?
т.е. есть список разделов, из которых я вывожу 5 новостей. После каждого раздела идет кнопка " показать далее", при нажатии на которую подгружаются данные, но для всех разделов, а как ограничить их текущим разделом? т.е. что бы при нажатии далее у раздела 2, подгрузились новости только в этот раздел?
$(document).ready(function(){
$(document).on('click', '.load_more', function(){
var targetContainer = $('.bx_catalog_list_home'), // Контейнер, в котором хранятся элементы
url = $('.load_more').attr('data-url'); // URL, из которого будем брать элементы
$('.load_more').remove();
if (url !== undefined) {
$.ajax({
type: 'GET',
url: url,
dataType: 'html',
success: function(data){
// Удаляем старую навигацию
var elements = $(data).find('.bx_catalog_item'), // Ищем элементы
pagination = $(data).find('.load_more').filter(':last');// Ищем навигацию
targetContainer.append(elements); // Добавляем посты в конец контейнера
targetContainer.append(pagination); // добавляем навигацию следом
}
})
}
});
});
Несколько раз перепроверил свой код, но так и не смог воспроизвести ситуацию дублирования.
Хотелось бы ещё добавить, чтобы не было дублей нужно сделать так
pagination = $(data).find('.load_more').filter(':last');// Ищем навигацию
В конечном итоге у меня получилось
$(document).ready(function(){
$(document).on('click', '.load_more', function(){
var targetContainer = $('.bx_catalog_list_home'), // Контейнер, в котором хранятся элементы
url = $('.load_more').attr('data-url'); // URL, из которого будем брать элементы
$('.load_more').remove();
if (url !== undefined) {
$.ajax({
type: 'GET',
url: url,
dataType: 'html',
success: function(data){
// Удаляем старую навигацию
var elements = $(data).find('.bx_catalog_item'), // Ищем элементы
pagination = $(data).find('.load_more').filter(':last');// Ищем навигацию
targetContainer.append(elements); // Добавляем посты в конец контейнера
targetContainer.append(pagination); // добавляем навигацию следом
}
})
}
});
});
php и css без изменений
Здравствуйте. Сделал всё по инструкции, но что-то пошло не так... Сделал 4 новости. В "NEWS_COUNT" указал 3. При нажатии на кнопку просто дублируется ещё раз список из тех же 3 новостей, которые сразу видны и без нажатия (((
Выложите код на codepen, вслепую сложно что-то сказать)
Вывожу список новостей на главной странице, шаблон списка лежит в /bitrix/components/md/news.list/templates, шаблон навигации добавил в /bitrix/components/bitrix/system.pagenavigation/templates/
Подскажи, а как сделать кнопку "Посмотреть все"?
Алгоритм будет таким:
1. В настройках компонента проставляется галочка "Показывать ссылку "Все"
2. Для отображения всех элементов надо передать get-запрос с параметром SHOWALL_1=1. Делаем AJAX запрос с этим параметром, к файлу компонента. Компонент должен вернуть все записи.
3. Вставка блока и отображение на странице без существенных изменений.
у меня заработало после небольшой правки:
Дмитрий, спасибо! Много вариантов решения перепробовал, только Ваше заработало
Спасибо за отзыв)
Классное решение - все просто и функционально!
Спасибо)
А что, если у нас будет 60 новостей, на одной странице мы хотим выводить 16 новостей, если использовать ваш пример, то при нажатие "показать еще" выводит след. 16 новостей и при дальнейшей попытке нажать "посмотреть еще", он повторяет вывод новостей, которые были выгружены во второй раз
Добрый день) Такие частные случаи я не рассматривал, но, думаю не проблема в качестве "первой подгрузки" получать не вторую, а, например, четвертую страницу. Единственное ограничение - первоначальниый вывод (60 элементов) должны делиться на количество подгружаемых (у вас 16, возьмите 20 для удобства) без остатка, иначе будут пропадать элементы.
Здравствуйте
Подскажите пожалуйста, есть ли возможность прикрутить два таких списка новостей с ajax подгрузкой на одной странице?
Попробовал, первый отрабатывает как положено, а вот второй начинает при клике на "Показать еще" дублировать новости из своего списка.
Хотя нашел ответ на свой вопрос.
Путем включения у компонентов AJAX_MODE => Y
и в компоненте подставить параметр AJAX_OPTION_ADDITIONAL присвоив ему уникальное значение.
Решил!
Проблема была в том, что в шаблоне постраничной навигации я прописал параметр
$paramName = "PAGEN_1";
а надо было:
$paramName = "PAGEN_" . $arResult["NavNum"];
Да, ваш подход более верный. Внес изменения в статью)
Огромное спасибо!
В примере автора нужно заменить:
$url = $arResult["sUrlPathParams"] . "PAGEN_1=" . $plus;
НА:
$url = $arResult["sUrlPathParams"] . "PAGEN_".$arResult["NavNum"]."=".$plus;
Задал уникальные классы: load_more1, news-list1 и т. д.. Кэширование отключил.
Установил AJAX_MODE => Y и прописал уникальные AJAX_OPTION_ADDITIONAL в компонентах, но всё равно 2-й по списку компонент дублирует свои элементы.
Куда копать, уже не знаю.
Добрый день!)
Вообще, должно решаться очень просто: необходимо в скрипте и шаблоне компонента задать уникальные классы. Например: load_more1, news-list1 и тд. Надо проверить, не экспериментировал:)
Не хватает обработки истории браузера, при клике "Назад" - "Вперед" мы должны попадать в то же место, должны загружаться ранее загруженные страницы
Отличное предложение)
как реализовать?
А как сделать так, чтобы фокус не перемещался наверх страницы?