#javascript #event-handling #dom-events #toggle #accordion
Вопрос:
Я вижу, что класс активно добавляется в консоль для первого элемента, но только для первого элемента. Прослушиватель событий привязан к кнопке svg. Класс «открыть» превращает отображение «скрытого блока» в отображение: блок; в контейнере элементов
const faqDropDown = document.querySelector(".accordion-icon");
const faqContainer = document.querySelector(".item");
faqDropDown.addEventListener("click", function() {
faqContainer.classList.toggle("open");
});
.item { margin-bottom: 10px; }
p { margin: 0; }
svg { width 1em; height: 1em; margin: 10px; }
<div class="item">
<p class="number">01</p>
<p class="text">lorem ipsum ist?</p>
<svg
xmlns="http://www.w3.org/2000/svg"
class="accordion-icon"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 9l-7 7-7-7"
/>
</svg>
<div class="hidden-box">
<p>
Lorem ipsum, dolor sit amet consectetur adipisicing elit.
Et, tempore repudiandae. Minima, cupiditate totam nihil
laborum rem sit, est, ea et quaerat hic accusantium quos.
</p>
</div>
</div>
<div class="item">
<p class="number">02</p>
<p class="text">lorem ipsum ist?</p>
<svg
xmlns="http://www.w3.org/2000/svg"
class="accordion-icon"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 9l-7 7-7-7"
/>
</svg>
<div class="hidden-box">
<p>
Lorem ipsum, dolor sit amet consectetur adipisicing elit.
Et, tempore repudiandae. Minima, cupiditate totam nihil
laborum rem sit, est, ea et quaerat hic accusantium quos.
</p>
</div>
</div>
Ответ №1:
Оператору требуется обработка состояния всех элементов аккордеона. Таким образом, как и в приведенном примере, обработчик событий должен быть зарегистрирован для значка svg каждого элемента.
Затем обработчику необходимо не только позаботиться о состоянии переключения элемента, но также определить и обработать случай закрытия всех других элементов …
function handleAccordionItemStates({ currentTarget }) {
const currentItem = currentTarget.closest('.item');
const currentAccordion = currentItem.closest('.accordion');
const isCloseOthers = !currentItem.classList.contains('open');
if (isCloseOthers) {
currentAccordion
.querySelectorAll('.item')
.forEach(item => {
if (item !== currentItem) {
item.classList.remove('open');
}
});
}
currentItem.classList.toggle('open');
}
function init() {
document
.querySelectorAll('.accordion-icon')
.forEach(elmNode =>
elmNode.addEventListener('click', handleAccordionItemStates)
);
}
init();
p { margin: 0; }
svg {
width 1em;
height: 1em;
transition: transform .3s ease-in;
}
.item { margin-bottom: 10px; }
.item p { float: left; margin-right: 10px; }
.item svg { float: right; margin-right: 50px; }
.hidden-box {
clear: both;
overflow: hidden;
padding-top: 5px;
transition: max-height .6s ease-in-out;
max-height: 0;
}
.item.open .hidden-box { max-height: 900px; }
.item.open svg { transform: rotate(180deg); }
<div class="accordion">
<div class="item">
<p class="number">01</p>
<p class="text">lorem ipsum</p>
<svg
xmlns="http://www.w3.org/2000/svg"
class="accordion-icon"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 9l-7 7-7-7"
/>
</svg>
<div class="hidden-box">
<p>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Et,
tempore repudiandae. Minima, cupiditate totam nihil laborum rem sit,
est, ea et quaerat hic accusantium quos.
</p>
</div>
</div>
<div class="item">
<p class="number">02</p>
<p class="text">accusantium quos</p>
<svg
xmlns="http://www.w3.org/2000/svg"
class="accordion-icon"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 9l-7 7-7-7"
/>
</svg>
<div class="hidden-box">
<p>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Et,
tempore repudiandae. Minima, cupiditate totam nihil laborum rem sit,
est, ea et quaerat hic accusantium quos.
</p>
</div>
</div>
<div class="item">
<p class="number">03</p>
<p class="text">cupiditate totam</p>
<svg
xmlns="http://www.w3.org/2000/svg"
class="accordion-icon"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 9l-7 7-7-7"
/>
</svg>
<div class="hidden-box">
<p>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Et,
tempore repudiandae. Minima, cupiditate totam nihil laborum rem sit,
est, ea et quaerat hic accusantium quos.
</p>
</div>
</div>
</div>
Ответ №2:
ваша проблема заключается в том, что вы используете querySelector
, который вернет первый встреченный объект, это означает, что он вернет только первый существующий элемент .item
.
Чтобы применить некоторые изменения к нескольким элементам с классом (я думаю , у вас их несколько class="item"
), вам нужно использовать querySelectorAll
, что вернет массив узлов, у которых есть класс item
.
ниже я оставил вам пример того, как использовать querySelectorAll
, а затем выполнить цикл над каждым узлом, а затем применить изменения, которые вы хотите.
примечание: если вы посмотрите на код, html был создан мной только для того, чтобы показать, что он работает (он меняет все элементы на красный). часть javascript-это та, которая изменилась, чтобы внести правильные изменения во все элементы. просто скопируйте и вставьте его в свой код, и он должен работать.
const faqDropDown = document.querySelector(".accordion-icon");
const faqContainers = document.querySelectorAll(".item");
faqDropDown.addEventListener("click", function() {
faqContainers.forEach(faqContainer => {
faqContainer.classList.toggle("open");
})
});
.open {
color: red;
}
<button class="accordion-icon">
toggle open
</button>
<div class="item">
item1
</div>
<div class="item">
item2
</div>
<div class="item">
item3
</div>
<div class="item">
item4
</div>
Комментарии:
1. Похоже на то, что я ищу! Однако я хочу, чтобы он открывал и закрывал только выпадающий список, на который я нажимаю. Как бы я это сделал?