30 lip 2017

Rozwijane menu

Najpierw budujemy strukturę html. Wszystko jest robione w scss, js w wersji ES6 i gulp
Do ES6 używam gulp-babel aby przekonwertować js do es2015

<div class="container">
  <div id="accorions">
    <div class="accordion">Section 1</div>
    <div class="panel">
      <p>Sauerkraut can be garnished with cored avocado, also try decorateing the cake with hollandaise sauce.
        Asparagus can be marinateed with crushed lettuce, also try flavoring the loaf with salsa verde.
        with lobsters drink cream.</p>
    </div>

    <div class="accordion">Section 2</div>
    <div class="panel">
      <p>Aww, raid me parrot, ye dead landlubber! Swashbuckling, coal-black whales cowardly vandalize a mighty, gutless
        scabbard.
        Scabbards sing on booty at port degas! Small, dead tobaccos darkly fight a black, lively dagger.
        seashells fall with love.</p>
    </div>

    <div class="accordion">Section 3</div>
    <div class="panel">
      <p>Turbulence at the bridge was the adventure of mineral, lowered to a gravimetric mermaid.
        Moon at the universe was the mystery of coordinates, feeded to a real planet.
        wisely handle a processor.</p>
    </div>
  </div>
</div>

Dodajemy trochę css, na początku importuję normalize

@import "normalize";

.container {
    max-width: 500px;
    margin: 200px auto;

}

.accordion {
    background-color: #eee;
    color: #444;
    cursor: pointer;
    padding: 18px;
    width: 100%;
    border: none;
    text-align: left;
    outline: none;
    font-size: 15px;
    transition: 0.4s;
    &:after {
        content: '\002B';
        color: #777;
        font-weight: bold;
        float: left;
        margin-right: 5px;
    }
    &:hover {
        background-color: #ddd;
    }
    &.active {
        background-color: #ddd;
        &:after {
            content: "\2212";
        }
    }
}

.panel {
    padding: 0 18px;
    background-color: white;
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.2s ease-out;
    li {
        list-style: none;
    }
}

Teraz najważniejsza część, dodajemy js

"use strict";

class Accordion {

  constructor(options) {
    this.options = options;
  }

  creatAccordion() {
    let acc = this.getAccordionName();

    [...acc].forEach((el, i) => {
      el.addEventListener('click', el => {
        if (this.options.type === true && !this.hasClass(el, this.options.activeName)) {
          this.removeActiveAndPanelHeight();
        }
        el.target.classList.toggle(this.options.activeName);
        let panel = el.target.nextElementSibling;
        if (panel.style.maxHeight) {
          panel.style.maxHeight = null;
        } else {
          panel.style.maxHeight = panel.scrollHeight + 'px';
        }
      })
    })

  }

  getAccordionName() {
    return document.getElementsByClassName(this.options.accordionName);
  }

  hasClass(element, cla) {
    return (' ' + element.className + ' ').indexOf(' ' + cla + ' ') > -1;
  }

  removeActiveAndPanelHeight() {
    const currentActive = document.querySelectorAll("." + this.options.activeName);
    const heightPanel = document.querySelectorAll("." + this.options.panelName);

    [...currentActive].forEach(ca => {
      ca.classList.remove(this.options.activeName);
    });

    [...heightPanel].forEach(hp => {
      hp.removeAttribute("style");
    });
  }
}

const options = {
  'accordionName': 'accordion',
  'activeName': 'active',
  'panelName': 'panel',
  'type': true
};

const accordion = new Accordion(options);
accordion.creatAccordion();

Przykład można zobaczyć pod tym adresem

Ostatni parametr w options czyli 'type': true lub false umożliwia sterowaniem zwijania menu, true powoduje że każde kliknięcie na menu zwija inne rozwinięte zaś false pozostawia rozwinięte każde kliknięcie.
Oczywiście options można przenieść do html aby z tego miejsca sterować nie musi być ten obiekt umieszczony w js.

Całość włącznie z gulpem można zobaczyć na github