Как создать многослойное аккордеонное меню? - PullRequest
0 голосов
/ 09 октября 2019

Я пытаюсь создать многослойное или вложенное аккордеонное меню, используя чистый JavaScript. Все работает правильно, ожидая одной проблемы: когда я нажимаю на один элемент меню, все реагирует.

Это не для текущего проекта. Я просто пытаюсь расширить свои знания после прохождения базового курса.

Я знаю, что простой, но раздутый способ исправить это состоит в том, чтобы повторить функции три раза, а затем специально нацелиться на каждый узел (это дажеправильное слово?) в массиве. Тем не менее, я представляю, что это будет неправильный способ делать вещи. Как вы увидите, я попытался создать цикл для нескольких переменных. Я думаю, что это может быть моей проблемой, потому что, похоже, именно это связывает их всех вместе.

var accordion = document.getElementsByClassName("accordion");
var dropdown = document.getElementsByClassName("dropdown");
var accordionArrow = document.getElementsByClassName("accordionArrow");
var dropdownArrow = document.getElementsByClassName("dropdownArrow");
var content = document.getElementsByClassName("content");

function accordionFunction() {
  for (j = 0, k = 0, l = 0, m = 0; j < dropdown.length, k < accordionArrow.length, l < dropdownArrow.length, m < content.length; j++, k++, l++, m++) {
    if (dropdown[j].style.maxHeight) {
      dropdown[j].style.maxHeight = null;
      accordionArrow[k].style.transform = null;
      content[m].style.maxHeight = null;
      dropdownArrow[l].style.transform = null;
    } else {
      dropdown[j].style.maxHeight = dropdown[j].scrollHeight + "px";
      accordionArrow[k].style.transform = "rotate(-135deg)";
    }
  }
};

for (var i = 0; i < accordion.length; i++) {
  accordion[i].addEventListener("click", accordionFunction);
};

function accordionSubmenu() {
  for (l = 0, m = 0; l < dropdown.length, m < content.length; l++, m++) {
    if (content[m].style.maxHeight) {
      content[m].style.maxHeight = null;
      dropdownArrow[l].style.transform = null;
    } else {
      content[m].style.maxHeight = content[m].scrollHeight + "px";
      dropdownArrow[l].style.transform = "rotate(-135deg)";
    }
  }
};

for (j = 0; j < dropdown.length; j++) {
  dropdown[j].addEventListener("click", accordionSubmenu)
};
body {
  margin: auto;
  width: 600px;
}

div {
  margin: auto;
}

.accordion {
  background-color: lightblue;
  color: white;
  padding: 3%;
  cursor: pointer;
  width: 300px;
  height: 50px;
}

.accordion .accordionArrow {
  border: solid white;
  border-width: 0 3px 3px 0;
  display: inline-block;
  padding: 3px;
  transform: rotate(45deg);
}

.dropdown {
  color: lightblue;
  padding-left: 3%;
  cursor: pointer;
  width: 300px;
  max-height: 0;
  overflow: hidden;
  transition-duration: 0.2s;
}

.dropdown .dropdownArrow {
  border: solid lightblue;
  border-width: 0 3px 3px 0;
  display: inline-block;
  padding: 3px;
  transform: rotate(45deg);
}

.content {
  font-weight: bold;
  transition: all 0.2s ease;
  padding-left: 5%;
  max-height: 0;
  overflow: hidden;
}
<div>
  <h2 class="accordion">Main 1<i class="accordionArrow"></i></h2>
  <h3 class="dropdown">Submenu 1<i class="dropdownArrow"></i></h3>
  <p class="content">Hello there. We are exposed.</p>
</div>
<div>
  <h2 class="accordion">Main 2<i class="accordionArrow"></i></h2>
  <h3 class="dropdown">Submenu 1<i class="dropdownArrow"></i></h3>
  <p class="content">Hello there. We are exposed again!</p>
</div>
<div>
  <h2 class="accordion">Main 3<i class="accordionArrow"></i></h2>
  <h3 class="dropdown">Submenu 1<i class="dropdownArrow"></i></h3>
  <p class="content">Hello there. We are exposed thrice!</p>
</div>

1 Ответ

0 голосов
/ 09 октября 2019

С помощью умного использования ключевого слова this (элемента, который вызвал обработчик события) и свойства nextElementSibling вы можете добиться этого более элегантным способом.

Я создал класс, чтобы сделатьelements max-height 0. Так что теперь я могу скрывать и показывать элементы, просто добавляя или удаляя этот класс.

В функции аккордеона я переключаю этот класс для элемента после выбранного элемента и удаляю класс для всех остальных.

В подменю аккордеона я просто переключаю класс в nextElementSibling.

Лично я бы создал другую html-структуру, где вы могли бы легче переключать классы, используя больше уровнейэлементы, так что вам понадобится только 1 функция для х количество подменю. Может быть, хороший новый вызов для вас.

document.querySelectorAll('.accordion').forEach((accordion) => accordion.addEventListener('click', function() {
  //Get All possible hidden elements and loop over it.
  document.querySelectorAll('.dropdown, .content').forEach((collapsible) => {
    //If current element is the same is the next sibling element of the event target toggle the class. Otherwise add it.
    if(collapsible === this.nextElementSibling) {
      collapsible.classList.toggle('maxHeightZero');
    }
    else {
      collapsible.classList.add('maxHeightZero');
    }
  });
}));

document.querySelectorAll('.dropdown').forEach((dropdown) => dropdown.addEventListener('click', function() {
  //toggle the nextElementSibling
  this.nextElementSibling.classList.toggle('maxHeightZero');
}));
body {
  margin: auto;
  width: 600px;
}

div {
  margin: auto;
}

.accordion {
  background-color: lightblue;
  color: white;
  padding: 3%;
  cursor: pointer;
  width: 300px;
  height: 50px;
}

.accordion .accordionArrow {
  border: solid white;
  border-width: 0 3px 3px 0;
  display: inline-block;
  padding: 3px;
  transform: rotate(45deg);
}

.dropdown {
  color: lightblue;
  padding-left: 3%;
  cursor: pointer;
  width: 300px;
  overflow: hidden;
  transition-duration: 0.2s;
}

.dropdown .dropdownArrow {
  border: solid lightblue;
  border-width: 0 3px 3px 0;
  display: inline-block;
  padding: 3px;
  transform: rotate(45deg);
}

.content {
  font-weight: bold;
  transition: all 0.2s ease;
  padding-left: 5%;
  overflow: hidden;
}

.maxHeightZero { 
  max-height: 0;
}
<div>
  <h2 class="accordion">Main 1<i class="accordionArrow"></i></h2>
  <h3 class="dropdown maxHeightZero">Submenu 1<i class="dropdownArrow"></i></h3>
  <p class="content maxHeightZero">Hello there. We are exposed.</p>
</div>
<div>
  <h2 class="accordion">Main 2<i class="accordionArrow"></i></h2>
  <h3 class="dropdown maxHeightZero">Submenu 1<i class="dropdownArrow"></i></h3>
  <p class="content maxHeightZero">Hello there. We are exposed again!</p>
</div>
<div>
  <h2 class="accordion">Main 3<i class="accordionArrow"></i></h2>
  <h3 class="dropdown maxHeightZero">Submenu 1<i class="dropdownArrow"></i></h3>
  <p class="content maxHeightZero">Hello there. We are exposed thrice!</p>
</div>
...