Для одного из проектов нужно было сделать аккордеон, решил показать в блоге, как его делать. Делаем аккордеон в блоке FAQ, поэтому там будут классы и стили со словом faq.
В вёрстке блок выглядит вот так. При клике должен показываться текст и иконка меняется с плюса на минус.
Логика
При клике на заголовок элемента, мы ищем его родителя и добавляем ему класс is-active
. В то же время удаляем такой класс у остальных элементов. Изначально контект и одна иконка скрыта. В стилях для блока с активным класом меняем отображения внутренних элементов.
Разметка
Сначала нам нужна разметка. В списке всего один элемент. Чтобы не
<div class="faqs-list">
<div class="faq faq-item">
<div class="faq-header">
<div class="faq-icon">
<img class="faq-icon-minus" src="./img/svg/faq-icon-minus.svg" alt="">
<img class="faq-icon-plus" src="./img/svg/faq-icon-plus.svg" alt="">
</div>
<div class="faq-title">Заголовок элемента</div>
</div>
<div class="faq-text">Текст элемента</div>
</div>
</div>
В разметке мы должны дать дополнительный класс с приставкой .js
, чтобы обращаться к нему из jQuery/Javascript. Дополнительный классы нужен, чтобы другой разработчик его не трогал. Чтобы понимал, что он не для стилей, а для интерактивности.
Нам нужно будет добавить 2 класса:
- для шапки —
js-faq-header
, - для элемента —
js-faq
Проставил классы в той же разметке. Выделил их жирным.
<div class="faqs-list">
<div class="faq faq-item js-faq">
<div class="faq-header js-faq-trigger">
<div class="faq-icon">
<img class="faq-icon-minus" src="./img/svg/faq-icon-minus.svg" alt="">
<img class="faq-icon-plus" src="./img/svg/faq-icon-plus.svg" alt="">
</div>
<div class="faq-title">Заголовок элемента</div>
</div>
<div class="faq-text">Текст элемента</div>
</div>
</div>
Стили
/* Стили по-умолчанию*/
.faq-icon-minus {
display: none;
}
.faq-text {
display: none;
}
/* Показываем текст */
.faq.is-active .faq-text {
display: block;
}
/* Меняем иконку */
.faq.is-active .faq-icon-minus {
display: block;
}
.faq.is-active .faq-icon-plus {
display: none;
}
Логика
При клике на faq-header
, мы ищем его родителя faq
и добавляем ему класс is-active
. А у всех остальных удаляем.
JavaScript
// Перебираем каждый элемент шапки
document.querySelectorAll('.js-faq-trigger').forEach(function(trigger) {
// Получаем родителя, элемент аккордеона
var parent = trigger.closest('.js-faq');
// клик по шапке
trigger.addEventListener('click', function(e) {
// если при клике у него уже есть активный класс
if (parent.classList.contains('is-active')) {
// то мы его удаляем
parent.classList.remove('is-active');
}
// если при клике мы не нашли у элемента активный класс
else {
// удаляем у всех элементов активный класс
document.querySelectorAll('.js-faq').forEach(function(item) {
item.classList.remove('is-active');
});
// добавляем класс тому элементу, по которому кликнули
parent.classList.add('is-active');
}
})
});
jQuery
// клик по шапке
$('.js-faq-trigger').on('click',function() {
// Получаем родителя, элемент аккордеона
var parent = $(this).closest('.js-faq');
// если при клике мы не нашли у элемента активный класс
if (parent.hasClass('is-active')) {
// то мы его удаляем
parent.removeClass('is-active');
}
else {
// удаляем у всех элементов активный класс
$('.js-faq').removeClass('is-active');
// добавляем класс тому элементу, по которому кликнули
parent.addClass('is-active');
}
})
Демо работы
Канал о фрилансе
Там я делюсь фишками о фрилансе: деньги, клиенты, автоматизация, фриланс. Раньше это был закрытый материал с платным доступом. Сейчас он открыт. Иногда подписчикам будет открываться платные материалы. Подписаться