Динамический список рубрик: полное руководство по внедрению кнопки показать скрыть
- Показывать справа: 0
В современном веб-дизайне важна не только привлекательность, но и удобство использования. Динамические элементы, такие как интерактивные списки рубрик или тегов, помогают пользователям быстрее находить нужную информацию, улучшая навигацию и, как следствие, SEO вашего сайта. В этом уроке мы разберем, как реализовать функционал "Показать/Скрыть" для списка рубрик, используя JavaScript (jQuery), HTML и CSS.
Введение: Зачем нужен динамический список рубрик?
Большое количество рубрик или тегов на сайте может привести к перегрузке страницы, затрудняя восприятие и навигацию. Скрывая часть элементов и предоставляя возможность их отображения по запросу пользователя, мы создаем более чистый и интуитивно понятный интерфейс. Это особенно актуально для страниц с большим количеством SEO-тегов или категорий товаров/услуг.
Шаг 1: HTML-структура
Основой для нашего динамического списка служит следующая HTML-разметка. Каждый список рубрик помещен в контейнер .seotags_cloud, а сам список имеет класс .seotags_list и уникальный атрибут data-id. Элементы списка — это ссылки <a>.
<div class="seotags_cloud">
<div class="seotags_list" data-id="1">
<!-- Здесь будут ссылки на рубрики -->
<a href="/vafelnye-plyajnye-polotenca1/" class="filter_button_gg myshow" style="display: inline-block;">Вафельные пляжные полотенца (37)</a>
<a href="/vafelnye-polotenca-s-risunkom1/" class="filter_button_gg myshow" style="display: inline-block;">Вафельные полотенца с рисунком (36)</a>
<!-- ... другие ссылки ... -->
</div>
<!-- ... другие .seotags_list блоки, если есть ... -->
</div>
Шаг 2: CSS-стили
CSS отвечает за внешний вид нашего списка. Важные стили включают классы для скрытия элементов (.myhide) и позиционирование кнопок "Показать/Скрыть" (.show__button_serv).
.seotags_cloud {
position: relative;
margin: 20px 0;
}
.seotags_cloud .seotags_list {
display: block;
position: relative;
font-size: 14px;
padding: 0;
width: auto;
}
.seotags_cloud .seotags_list a {
color: #065679;
background: #FFFFFF;
border: 1px solid #065679;
border-radius: 4px;
}
.seotags_cloud .seotags_list a
{
display: inline-block;
color: #23a1d1;
border: 1px solid #23a1d1;
padding: 4px 20px;
margin: 0 5px 10px 5px;
border-radius: 5px;
transition: 0.3s;
}
.seotags_list a.myhide {
display: none; /* Класс для скрытия элементов */
}
.show__button_serv {
visibility: hidden; /* Изначально скрыта, пока не будет определено положение */
position: absolute !important; /* Позволяет точно позиционировать кнопку */
bottom: 0px;
}
@media (max-width: 700px) {
.show__button_serv {
position: initial!important; /* На маленьких экранах кнопка становится обычной */
}
}
Шаг 3: JavaScript (jQuery) для динамической функциональности
Основная магия происходит в JavaScript. Этот код анализирует структуру, определяет, сколько элементов помещается в заданное количество строк, скрывает лишние и добавляет интерактивные кнопки "Показать/Скрыть".
/*@ ***********************
Рубрики
****************************/
// Ожидаем полной загрузки DOM перед выполнением скрипта
jQuery(document).ready(function(){
// filter_servicekol: Количество строк, которые должны быть видны сразу.
// Элементы будут скрываться, если они не помещаются в это количество строк.
var filter_servicekol = 2;
// filter_servicekol_was: Количество элементов, которое будет показываться за один клик по кнопке "Показать".
// Эта переменная определяет "шаг" пагинации или "порцию" элементов для отображения.
// Меньшее значение = более мелкая пагинация.
var filter_servicekol_was = 20; // Пример: показывать по 20 элементов за клик. Можно уменьшить.
// filter_servicekol__new: Массив, который будет хранить для каждого .seotags_list,
// сколько элементов должно быть видимо изначально (рассчитано по строкам).
var filter_servicekol__new = [];
/*@ ***********************
Добавляем две кнопки к списку скрыть и показать
****************************/
// Проверяем, существует ли хотя бы один блок с классом ".seotags_list"
if (jQuery(".seotags_list").length>0)
{
// Каждому блоку ".seotags_list" присваиваем data-id="n".
// Важно: если блоков несколько, data-id должен быть уникальным для каждого.
// В данном примере предполагается, что этот атрибут будет корректно назначен в HTML или здесь.
jQuery( ".seotags_list" ).each(function( index3 ) {
var obj2 = jQuery(this);
obj2.attr('data-id',index3 );
obj2.append(`<a data-id="`+index3+`" class="show__button_serv filter_button_tags more_button_tags" id="show" style="visibility: visible; display:none">
<i class="fa-solid fa-chevron-down"></i>
</a>
<a data-id="`+index3+`" style="display:none" class="hide__button_serv filter_button_tags more_button_tags" id="hide">
<i class="fa-solid fa-chevron-up"></i>
</a>`);
});
}
/****************** end@ */
// per: Вспомогательная переменная, используемая в обработчике клика по кнопке "Показать".
// Она получает значение filter_servicekol_was.
per = filter_servicekol_was;
// items_gr: Массив, который будет хранить jQuery-объекты всех ссылок (.filter_button_gg)
// для каждого блока .seotags_list.
var items_gr = [];
// i_mm_gr: Массив, хранящий количество видимых элементов (.filter_button_gg.myshow)
// для каждого блока .seotags_list.
var i_mm_gr = [];
// total_mm_gr: Массив, хранящий общее количество элементов, которое должно быть показано
// после нажатия на кнопку "Показать" (начиная с первого).
var total_mm_gr = [];
// start__sp_gr: Массив, вероятно, для хранения начальной позиции или количества элементов.
// В текущей логике не используется активно.
var start__sp_gr = [];
// new_global_start__postiton_tags: Функция для инициализации и перерасчета
// начального положения элементов. Определяет, сколько элементов помещается в заданное количество строк.
function new_global_start__postiton_tags() {
// Сброс переменных для корректного пересчета при каждом вызове
per = filter_servicekol_was;
items_gr = [];
i_mm_gr = [];
total_mm_gr = [];
start__sp_gr = [];
filter_servicekol__new = [];
// Перебираем каждый блок с классом ".seotags_list"
jQuery(".seotags_list").each(function(index) {
var obj2 = jQuery(this); // Текущий блок .seotags_list
// Перед расчетом, удаляем классы, которые могли быть добавлены ранее,
// и делаем все элементы видимыми, чтобы корректно измерить их положение.
obj2.find(".myhide").removeClass('myhide');
obj2.find(".myshow").removeClass('myshow');
obj2.find('a').css('display', 'inline-block');
var counter = {}; // Счетчик для определения элементов, находящихся в одной строке (по Y-координате)
// Проходим по всем ссылкам внутри текущего блока .seotags_list
obj2.find("a").each(function(index) {
var obj = jQuery(this); // Текущая ссылка
// Игнорируем кнопки "Показать"/"Скрыть", обрабатываем только элементы списка
if (obj.hasClass('filter_button_tags') == false) {
obj.addClass('filter_button_gg'); // Добавляем общий класс для всех элементов рубрик
var offset2 = obj.offset(); // Получаем координаты элемента
var offset = 1 * offset2.top; // Получаем Y-координату (верхнюю границу элемента)
// Если Y-координата больше 0 (элемент видим), увеличиваем счетчик для этой строки.
// Это позволяет определить, сколько элементов помещается в одну строку.
if (offset > 0)
counter[offset] = counter[offset] ? counter[offset] + 1 : 1;
}
});
// console.log(counter); // Отладочный вывод: показывает, сколько элементов в каждой строке
var kol_m = 0; // Общее количество элементов, которые должны быть видны по умолчанию
var k = 1; // Вспомогательная переменная для цикла (счетчик строк)
// Перебираем счетчик строк (объект 'counter')
// Цель: определить, сколько элементов помещается в первые 'filter_servicekol' строк.
for (property in counter) {
// Добавляем количество элементов из текущей строки к общему счетчику видимых элементов
kol_m += counter[property] * 1;
k = k + 1; // Увеличиваем счетчик строк
// Прерываем цикл, если мы прошли количество строк, заданное в filter_servicekol
if (k > filter_servicekol) {
break;
}
}
// console.log(' kol_m =' + kol_m); // Отладочный вывод
// console.log(' filter_button_gg total =' + obj2.find(".filter_button_gg").length); // Отладочный вывод
// Показываем кнопку "Показать", если она была скрыта
obj2.find(".show__button_serv").show();
// Если общее количество элементов (.filter_button_gg) равно рассчитанному количеству видимых элементов (kol_m),
// значит, все элементы помещаются и скрывать ничего не нужно. В этом случае скрываем обе кнопки.
if (obj2.find(".filter_button_gg").length == (kol_m)) {
obj2.find(".more_button_tags").hide(); // Скрываем обе кнопки "Показать"/"Скрыть"
}
// Сохраняем рассчитанное количество видимых элементов для текущего блока .seotags_list.
// Это значение будет использоваться в функции start__postiton_tags.
filter_servicekol__new.push(kol_m);
// Изначально скрываем кнопку "Скрыть"
obj2.find(".hide__button_serv").hide();
}); // Конец цикла по .seotags_list
} // Конец функции new_global_start__postiton_tags
// start__postiton_tags: Функция для установки начального состояния видимости элементов.
// Она применяет классы 'myhide' (для скрытия) и 'myshow' (для показа) на основе расчетов из new_global_start__postiton_tags.
function start__postiton_tags() {
// Перебираем каждый блок с классом ".seotags_list"
jQuery(".seotags_list").each(function(index3) {
var obj2 = jQuery(this); // Текущий блок .seotags_list
var kol = 0; // Счетчик элементов в текущем блоке
// Сначала скрываем все элементы, которые не должны быть видны по умолчанию,
// и удаляем класс 'myshow', чтобы начать заново.
obj2.find(".filter_button_gg").hide();
obj2.find(".myshow").removeClass('myshow');
var obh_k = 0; // Вспомогательная переменная для получения позиции предыдущего видимого элемента
// Проходим по всем ссылкам внутри текущего блока .seotags_list
obj2.find("a").each(function(index) {
var obj = jQuery(this); // Текущая ссылка
// Обрабатываем только ссылки, которые не являются кнопками
if (obj.hasClass('filter_button_tags') == false) {
kol++; // Увеличиваем счетчик элементов
// Если текущий элемент (kol) больше, чем рассчитанное количество видимых элементов (filter_servicekol__new[index3]),
// то этот элемент должен быть скрыт.
if (kol > filter_servicekol__new[index3] && obj.hasClass('filter_button_tags_active') == false) {
// Не видимые элементы - присваиваем класс 'myhide'
obj.addClass('myhide');
// Пытаемся установить позицию кнопки "Показать" справа от последнего видимого элемента.
// Эта часть требует, чтобы 'obh_k' был корректно установлен как предыдущий видимый элемент.
var left = obh_k.position().left * 1; // Получаем левое смещение предыдущего видимого элемента
var w = obh_k.width() * 1; // Получаем ширину предыдущего видимого элемента
var dop_ww = 50; // Дополнительное смещение для кнопки "Показать"
// Уменьшаем смещение на очень маленьких экранах
if (jQuery(window).width() < 350) {
var dop_ww = 15;
}
// Применяем CSS к кнопке "Показать" для установки ее позиции
obj2.find(".show__button_serv").css('left', (left + w + dop_ww));
} else {
// Видимые элементы - присваиваем класс 'myshow' и убеждаемся, что они отображаются
obh_k = obj; // Обновляем 'obh_k' текущим видимым элементом
obj.addClass('myshow'); // Добавляем класс 'myshow'
obj.css('display', 'inline-block'); // Убеждаемся, что элемент виден
}
}
}); // Конец цикла по ссылкам
}); // Конец цикла по .seotags_list
} // Конец функции start__postiton_tags
// filter__analiz: Основная функция, которая запускает все процессы инициализации и расчета.
// Она вызывается при загрузке страницы и при изменении размера окна.
function filter__analiz() {
// Сначала пересчитываем начальное положение и видимость элементов
new_global_start__postiton_tags();
// Затем применяем эти настройки, скрывая/показывая элементы
start__postiton_tags();
// Инициализация массивов для хранения данных по каждому блоку .seotags_list
jQuery(".seotags_list").each(function(index) {
var obj = jQuery(this); // Текущий блок .seotags_list
// Сохраняем jQuery-объект всех ссылок (.filter_button_gg) для этого блока
// Используем data-id для индексации массива
items_gr[obj.data('id') * 1] = obj.find('.filter_button_gg');
// Сохраняем количество видимых элементов (.filter_button_gg.myshow) для этого блока
i_mm_gr[obj.data('id') * 1] = obj.find('.filter_button_gg.myshow').length;
// Инициализируем счетчик показанных элементов, который будет увеличиваться при клике на "Показать"
total_mm_gr[obj.data('id') * 1] = 0;
// Инициализируем начальное положение (не используется в текущей логике)
start__sp_gr[obj.data('id') * 1] = 0;
});
// Делаем кнопки "Показать" видимыми после всех расчетов
jQuery(".show__button_serv").css('visibility', 'visible');
}
// Обработчик клика по кнопке "Показать"
jQuery(".show__button_serv").on("click", function() {
var obj = jQuery(this); // Текущая кнопка "Показать"
var index_gr = obj.data('id') * 1; // Получаем data-id текущего блока .seotags_list
obj.addClass('position_initial'); // Добавляем класс (возможно, для стилизации или анимации)
// Увеличиваем общее количество элементов, которое должно быть показано.
// Добавляем 'per' (количество элементов за клик, равное filter_servicekol_was)
i_mm_gr[index_gr] = i_mm_gr[index_gr] + per;
// Обновляем общее количество показанных элементов
total_mm_gr[index_gr] = i_mm_gr[index_gr];
// Показываем элементы, начиная с первого, до рассчитанного общего количества
// slice(0, N) берет первые N элементов
items_gr[index_gr].slice(0, total_mm_gr[index_gr]).css('display', 'inline-block');
// Проверяем, достигли ли мы конца списка (показаны все доступные элементы)
if (total_mm_gr[index_gr] >= items_gr[index_gr].length) {
$(this).hide(); // Скрываем кнопку "Показать"
// Показываем кнопку "Скрыть" для этого блока
$('.hide__button_serv[data-id="' + index_gr + '"]').show();
} else {
// Если список еще не полностью показан, кнопка "Показать" остается видимой
$(this).show();
}
});
// Обработчик клика по кнопке "Скрыть"
$("body").on("click", ".hide__button_serv", function() {
var obj = jQuery(this); // Текущая кнопка "Скрыть"
var index_gr = obj.data('id') * 1; // Получаем data-id текущего блока .seotags_list
obj.hide(); // Скрываем кнопку "Скрыть"
// Здесь происходит "сброс" до начального состояния.
// Скрываются все, кроме тех, что должны быть видны по умолчанию.
// Обращение к '.myhide' здесь может быть не совсем явным, но эффект достигается
// тем, что после этого пересчитывается количество видимых элементов (myshow).
jQuery('.seotags_list[data-id="' + index_gr + '"]').find('.myhide').hide(),
// Показываем кнопку "Показать" и убираем класс 'position_initial'
jQuery('.show__button_serv[data-id="' + index_gr + '"]').show();
jQuery('.show__button_serv[data-id="' + index_gr + '"]').removeClass('position_initial');
// Сбрасываем счетчики для корректного отображения при следующем нажатии "Показать".
// Пересчитываем количество видимых элементов (myshow) в текущем блоке.
i_mm_gr[index_gr] = jQuery('.seotags_list[data-id="' + index_gr + '"]').find('.filter_button_gg.myshow').length;
// Сбрасываем общее количество показанных элементов для следующего цикла "Показать".
total_mm_gr[index_gr] = 0;
});
// Запускаем функцию инициализации filter__analiz с небольшой задержкой (100ms).
// Это нужно, чтобы скрипт выполнился после полной отрисовки DOM и корректного расчета размеров элементов.
// setTimeout(filter__analiz, 100);
// Альтернативный, более надежный способ - использовать window.addEventListener("load", ...),
// но setTimeout также часто применяется в подобных случаях.
// Для данного случая, где фильтрация нужна сразу, setTimeout работает.
// Перезапуск анализа при изменении размера окна браузера.
// Это обеспечивает адаптивность: при изменении ширины экрана пересчитывается,
// сколько элементов помещается в заданное количество строк.
jQuery(window).resize(function() {
setTimeout(filter__analiz, 100);
});
/****************** end@ */
}); // Конец jQuery(document).ready
Заключение
Реализация динамического списка рубрик с функциями "Показать/Скрыть" — это отличный способ улучшить UX и положительно повлиять на SEO вашего сайта. Пользователи получают более чистый интерфейс, а поисковые системы — структурированную информацию. Вы можете легко адаптировать значения filter_servicekol (количество видимых строк) и filter_servicekol_was (шаг показа элементов) под нужды вашего проекта.