AllDecay
@AllDecay
Вечно отдыхающий.

Как правильно сделать выпадающий div при нажатии?

Имею такой html код (ненужные участки подтер за ненадобностью)
<div class="tab-pane" for="standart tabs_containers" id="tab0">
	<div class="effectiv_bar" style="width: 25%">25%</div>
	<div class="effectiv_color" style="width: 25%"></div>
	<div class="big_block">
		<button class="material_info">подробнее о материале</button>
	</div>
	<div class="desc">
		<ul style="padding: 0;">
тут какой-то текст
		</ul>
	</div>
</div>

Блоку "desc" прописываю следующие стили:
.desc{
       display: none;
}

И отлавливаю нажатия следующим js:
var acc = document.getElementsByClassName("material_info");
var i;
												
for (i = 0; i < acc.length; i++) {
	acc[i].addEventListener("click", function() {
	this.classList.toggle("active");
        if (document.getElementsByClassName("desc")[i].style.display == "block") {
		document.getElementsByClassName("desc")[i].style.display = "none";
	} else {
		document.getElementsByClassName("desc")[i].style.display = "block";
	}
});
}

В итоге получаю в консоли: Cannot read property 'style' of undefined и отсутствие появляющегося блока. В чем ошибка?
  • Вопрос задан
  • 145 просмотров
Решения вопроса 1
0xD34F
@0xD34F Куратор тега JavaScript
То, что значение i в момент выполнения document.getElementsByClassName("desc")[i]
будет тем же, что и в момент выполнения acc[i].addEventListener есть ни на чём не основанная фантазия, не соответствующая реальности.

Вот если вы объявите i в заголовке цикла с помощью let - тогда да, работать будет.

Но вообще, создавать отдельные обработчики клика для каждой кнопки и обращаться по индексу к элементам .desc нет необходимости. Можно от кликнутой кнопки подняться до .tab-pane и там переключить класс, который изменит видимость .desc:

.active .desc {
  display: block;
}

const itemSelector = '.tab-pane';
const buttonSelector = `${itemSelector} .material_info`;
const activeClass = 'active';

// слушаем клики на кнопках
document.querySelectorAll(buttonSelector).forEach(function(n) {
  n.addEventListener('click', this);
}, e => e.target.closest(itemSelector).classList.toggle(activeClass));

// или, применяем делегирование - назначаем обработчик один раз общему предку кнопок,
// внутри проверяем, где случился клик
document.addEventListener('click', ({ target: t }) => {
  if (t.matches(buttonSelector)) {
    t.closest(itemSelector).classList.toggle(activeClass);
  }
});
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы