Создание многослойных аккордеонов на чистом JS и использование nextElementSibling - PullRequest
1 голос
/ 19 октября 2019

Новое в Javascript. Недавно я опубликовал вопрос о создании нескольких многослойных аккордеонов. Я получил отличную обратную связь, но кто-то упомянул, что, если мой HTML был настроен правильно, я мог бы достичь той же цели, используя nextElementSibling и, таким образом, получить намного более чистый JS.

Я понял, как это сделать, используя только выбор запроса. См. Приведенный ниже пример:

HTML:

<div class="mainAccordion">
    <h2>dropdown one</h2>
    <h3>dropdown two</h3>
    <p>content content content content</p>
</div>

CSS:

.mainAccordion {
    background-color:lightblue;
    width:200px;
    margin:auto;
    padding:3%;
}
.mainAccordion :nth-child(1){
    background-color: blue;
    padding:3%;
    cursor:pointer;
    color:white;
}

.mainAccordion :nth-child(2){
    background-color:yellow;
    cursor:pointer;
    max-height:0;
    overflow:hidden;
}

.mainAccordion :nth-child(3){
    font-weight:bold;
    max-height:0;
    overflow:hidden;
}

ИJS:

var mainAccordion = document.querySelector(".mainAccordion").addEventListener("click", function(e) {
    if (e.target.nextElementSibling.style.maxHeight) {
        e.target.nextElementSibling.style.maxHeight = null;
    } else {
        e.target.nextElementSibling.style.maxHeight = e.target.nextElementSibling.scrollHeight + "px";
    }
});

Работает как задумано. Однако, когда я ввожу несколько многослойных аккордеонов и переключаюсь на «querySelectorAll», он перестает работать. Также в зависимости от браузера иногда появляется сообщение об ошибке, в котором говорится, что мой addEventListener не является функцией.

См. Ниже:

HTML:

<div class="mainAccordion">
    <h2>dropdown one</h2>
    <h3>dropdown two</h3>
    <p>content content content content</p>
</div>

<div class="mainAccordion">
    <h2>dropdown one</h2>
    <h3>dropdown two</h3>
    <p>content content content content</p>
</div>

CSS:

body {
    display:flex;
    width: 900px;
    margin:auto;
}
.mainAccordion {
    background-color:lightblue;
    width:200px;
    margin:auto;
    padding:3%;
}
.mainAccordion :nth-child(1){
    background-color: blue;
    padding:3%;
    cursor:pointer;
    color:white;
}

.mainAccordion :nth-child(2){
    background-color:yellow;
    cursor:pointer;
    max-height:0;
    overflow:hidden;
}

.mainAccordion :nth-child(3){
    font-weight:bold;
    max-height:0;
    overflow:hidden;
}

и JS:

var mainAccordion = document.querySelectorAll(".mainAccordion").addEventListener("click", function(e) {
    if (e.target.nextElementSibling.style.maxHeight) {
        e.target.nextElementSibling.style.maxHeight = null;
    } else {
        e.target.nextElementSibling.style.maxHeight = e.target.nextElementSibling.scrollHeight + "px";
    }
});

Я пытался изменить "querySelectorAll (". MainAccordion") to getElementsByClassName (" mainAccordion "), но также не работает.

Есть ли какое-либо отношение к forEach?

Примечание: я знаю, что вы также можете достичь той же цели, переключив класс, который имеет"максимальная высота: 0; переполнение: скрыто". Однако именно так меня изначально учили делать аккордеоны.

Это для моей собственной практики.

Я ценю помощь.

Ответы [ 2 ]

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

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

querySelectorAll() возвращает список. Вы можете использовать его с forEach, как это

  var mainAccordion = document.querySelectorAll(".mainAccordion");
  console.log(mainAccordion);
  mainAccordion.forEach(accordion => {
    accordion.addEventListener("click", function(e) {
      if (e.target.nextElementSibling.style.maxHeight) {
        e.target.nextElementSibling.style.maxHeight = null;
      } else {
        e.target.nextElementSibling.style.maxHeight =
          e.target.nextElementSibling.scrollHeight + "px";
      }
    });
  });
0 голосов
/ 19 октября 2019

Попробуйте:

let accordionElements = document.querySelectorAll(".mainAccordion");

    accordionElements.forEach(element => {
        element.addEventListener("click", function(e) {
            if (e.target.nextElementSibling.style.maxHeight) {
                e.target.nextElementSibling.style.maxHeight = null;
            } else {
                e.target.nextElementSibling.style.maxHeight = e.target.nextElementSibling.scrollHeight + "px";
            }
        })
    });

Это потому, что с querySelector () возвращается HTML-элемент. С querySelectorAll () это NodeList. В вашем примере кода вы пытаетесь прикрепить событие к списку узлов, что невозможно.

Необходимо выполнить цикл внутри, а затем прикрепить событие к каждому элементу HTML внутри.

...