← Назад в «Блог»
1 274

Аккордеон на jQuery/JavaScript

Для одного из проектов нужно было сделать аккордеон, решил показать в блоге, как его делать. Делаем аккордеон в блоке FAQ, поэтому там будут классы и стили со словом faq.

В вёрстке блок выглядит вот так. При клике должен показываться текст и иконка меняется с плюса на минус.

Аккордеон на jQuery/JavaScript 1

Логика

При клике на заголовок элемента, мы ищем его родителя и добавляем ему класс 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');  
    }
})

Демо работы

Аккордеон на jQuery/JavaScript 2
Полезно
6
1
Непонятно
2
Поделиться
Отправить
Линкануть
Вотсапнуть

Канал о фрилансе

Там я делюсь фишками о фрилансе: деньги, клиенты, автоматизация, фриланс. Раньше это был закрытый материал с платным доступом. Сейчас он открыт. Иногда подписчикам будет открываться платные материалы.

Подписаться
← Назад в «Блог»

12 комментария

Огромное спасибо, все получилось!

Рад стараться. Может быть у вас есть на примете библиотеки, о которых вы бы хотели узнать подробнее?

https://lincorwatches.com/ — или вот еще пример интересной анимации… было бы интересно посмотреть разбор примера на основе их скрипта

ничего не понял ,много специфики, а очень жаль!

Может вы подскажете в чем дело?

Правлю чужой код. Вот такой. А мне в консоли выдается, что ошибка Uncaught SyntaxError: missing ) after argument list.

<script>

      (document).ready(function(){

         var bLazy = new Blazy({

          loadInvisible: true, // загрузка скрытых изображений

          container: ‘.slick-track, b-lazy’ // загрузка скрытых изображений слайдера

        });

        bLazy.revalidate();

      }

    </script>

Что то у меня нифига не получается, уже все перепробовал.

Есть код с изображениями:

<a class=»product-image» href=»$ENTRY_URL$»>

<img class=»b-lazy» alt=»$NAME$» src=»/images/blank-1-.gif» data-src-mobile=»<?if($SMALL$)?>$SMALL$<?else?>/img404/big.svg<?endif?>» data-src=»<?if($THUMB$)?>$THUMB$<?else?>/img404/big.svg<?endif?>» class=»gphoto» id=»$BLOCK_PREF$-gphoto-$ID$» title=»$NAME$»>

</a>

И пример вашего кода, который я подставляю:

<script>

var bLazy = new Blazy({

 breakpoints: [{

 width: 480, // Max width

 src: ‘data-src-mobile’ // Name atribut

 }]

});

</script>

Как он работает не понимаю, растолкуйте. По идеи должно быть если оригинал фото товара размерами больше 480х480, тогда формируется уменьшенное фото и оператор $SMALL$ выводит ссылку на уменьшенное фото.

Размер превью оператора $SMALL$, 80*80

и при этом еще постоянно ошибка в консоли:

Uncaught ReferenceError: Blazy is not defined

Если не трудно можете посмотреть в консоли:

https://www.aksshop.ru/shop/shtatnye-magnitoly-unison/magnitoly-unison

Здравствуйте. Подскажите, вот мой код, который я подключаю отдельным файлом
/*!
hey, [be]Lazy.js — v1.8.2 — 2016.10.25
A fast, small and dependency free lazy load script (https://github.com/dinbror/blazy)
(c) Bjoern Klinggaard — @bklinggaard — http://dinbror.dk/blazy
*/
(function(q,m){«function»===typeof define&&define.amd?define(m):»object»===typeof exports?module.exports=m():q.Blazy=m()})(this,function(){function q(b){var c=b._util;c.elements=E(b.options);c.count=c.elements.length;c.destroyed&&(c.destroyed=!1,b.options.container&&l(b.options.container,function(a){n(a,»scroll»,c.validateT)}),n(window,»resize»,c.saveViewportOffsetT),n(window,»resize»,c.validateT),n(window,»scroll»,c.validateT));m(b)}function m(b){for(var c=b._util,a=0;a=c.left&&b.bottom>=c.top&&b.left<=c.right&&b.top<=c.bottom}function z(b,c,a){if(!t(b,a.successClass)&&(c||a.loadInvisible||0<b.offsetWidth&&0<b.offsetHeight))if(c=b.getAttribute(u)||b.getAttribute(a.src)){c=c.split(a.separator);var d=c[A&&1<c.length?1:0],e=b.getAttribute(a.srcset),g="img"===b.nodeName.toLowerCase(),p=(c=b.parentNode)&&"picture"===c.nodeName.toLowerCase();if(g||void 0===b.src){var h=new Image,w=function(){a.error&&a.error(b,"invalid");v(b,a.errorClass);k(h,"error",w);k(h,"load",f)},f=function(){g?p||B(b,d,e):b.style.backgroundImage='url("'+d+'")';x(b,a);k(h,"load",f);k(h,"error",w)};p&&(h=b,l(c.getElementsByTagName("source"),function(b){var c=a.srcset,e=b.getAttribute(c);e&&(b.setAttribute("srcset",e),b.removeAttribute(c))}));n(h,"error",w);n(h,"load",f);B(h,d,e)}else b.src=d,x(b,a)}else"video"===b.nodeName.toLowerCase()?(l(b.getElementsByTagName("source"),function(b){var c=a.src,e=b.getAttribute(c);e&&(b.setAttribute("src",e),b.removeAttribute(c))}),b.load(),x(b,a)):(a.error&&a.error(b,"missing"),v(b,a.errorClass))}function x(b,c){v(b,c.successClass);c.success&&c.success(b);b.removeAttribute(c.src);b.removeAttribute(c.srcset);l(c.breakpoints,function(a){b.removeAttribute(a.src)})}function B(b,c,a){a&&b.setAttribute("srcset",a);b.src=c}function t(b,c){return-1!==(" "+b.className+" ").indexOf(" "+c+" ")}function v(b,c){t(b,c)||(b.className+=" "+c)}function E(b){var c=[];b=b.root.querySelectorAll(b.selector);for(var a=b.length;a—;c.unshift(b[a]));return c}function C(b){f.bottom=(window.innerHeight||document.documentElement.clientHeight)+b;f.right=(window.innerWidth||document.documentElement.clientWidth)+b}function n(b,c,a){b.attachEvent?b.attachEvent&&b.attachEvent("on"+c,a):b.addEventListener(c,a,{capture:!1,passive:!0})}function k(b,c,a){b.detachEvent?b.detachEvent&&b.detachEvent("on"+c,a):b.removeEventListener(c,a,{capture:!1,passive:!0})}function l(b,c){if(b&&c)for(var a=b.length,d=0;d<a&&!1!==c(b[d],d);d++);}function D(b,c,a){var d=0;return function(){var e=+new Date;e-d<c||(d=e,b.apply(a,arguments))}}var u,f,A,y;return function(b){if(!document.querySelectorAll){var c=document.createStyleSheet();document.querySelectorAll=function(a,b,d,h,f){f=document.all;b=[];a=a.replace(/\[for\b/gi,"[htmlFor").split(",");for(d=a.length;d—;){c.addRule(a[d],"k:v");for(h=f.length;h—;)f[h].currentStyle.k&&b.push(f[h]);c.removeRule(0)}return b}}var a=this,d=a._util={};d.elements=[];d.destroyed=!0;a.options=b||{};a.options.error=a.options.error||!1;a.options.offset=a.options.offset||100;a.options.root=a.options.root||document;a.options.success=a.options.success||!1;a.options.selector=a.options.selector||".b-lazy";a.options.separator=a.options.separator||"|";a.options.containerClass=a.options.container;a.options.container=a.options.containerClass?document.querySelectorAll(a.options.containerClass):!1;a.options.errorClass=a.options.errorClass||"b-error";a.options.breakpoints=a.options.breakpoints||!1;a.options.loadInvisible=a.options.loadInvisible||!1;a.options.successClass=a.options.successClass||"b-loaded";a.options.validateDelay=a.options.validateDelay||25;a.options.saveViewportOffsetDelay=a.options.saveViewportOffsetDelay||50;a.options.srcset=a.options.srcset||"data-srcset";a.options.src=u=a.options.src||"data-src";y=Element.prototype.closest;A=1=window.screen.width)return u=a.src,!1});setTimeout(function(){q(a)})}});

document.addEventListener(«DOMContentLoaded», function(event) {
var bLazy = new Blazy({
offset: 50,
});
});
Вот кусок html, где находится изображение

картинка-прелоадер загружается, а основная — нет.
Ошибок в консоли не выдает. Файл со скриптом загружается. Такое ощущение, что скрипт не отрабатывает. Подскажите, в чем может быть проблема

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *