Аккордеон на чистом Javascript

133
09 августа 2019, 07:10

var panelItem = document.querySelectorAll('.panel-title'), 
  bodyItem = document.querySelectorAll('.panel-body'); 
 
 
panelItem.forEach(function(item, i, panelItem) { 
  item.addEventListener('click', function(e) { 
    if (this.classList.contains('panel-active')) { 
      bodyItem[i].classList.remove('active'); 
      this.classList.remove('panel-active'); 
    } else { 
      item[i].classList.remove('panel-active'); 
      panelItem[i].classList.remove('panel-active'); 
      bodyItem[i].classList.remove('active'); 
      this.classList.add('panel-active'); 
      this.nextElementSibling.classList.add('active'); 
    } 
  }); 
});
* { 
  padding: 0; 
  margin: 0; 
} 
 
.container { 
  max-width: 700px; 
  margin: 0 auto; 
  padding-top: 20px; 
} 
 
.panel { 
  margin-bottom: 5px; 
} 
 
.panel-title { 
  padding: 10px 15px; 
  background-color: #f5f5f5; 
  border: 1px solid #ddd; 
  font-size: 16px; 
  color: #333; 
  border-radius: 4px; 
  font-family: 'Helvetica'; 
  font-weight: 300; 
  cursor: pointer; 
  margin-bottom: 5px; 
} 
 
.panel-body { 
  padding: 15px; 
  border: 1px solid #ddd; 
  border-bottom-left-radius: 4px; 
  border-bottom-right-radius: 4px; 
  display: none; 
  margin-bottom: 10px; 
  background: #fff; 
} 
 
.panel-active { 
  margin-bottom: 0; 
  border-bottom: 0; 
  border-bottom-left-radius: 0; 
  border-bottom-right-radius: 0; 
  text-decoration: underline; 
} 
 
.active { 
  display: block; 
}
<div class="container"> 
  <div class="panel-group"> 
    <h3 class="panel-title">Group Item #1</h3> 
    <div class="panel-body"> 
      Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты. Переписывается реторический за, щеке сбить, если большой языкового ему алфавит составитель силуэт меня страну рукопись языком вопроса толку оксмокс она. 
    </div> 
    <h3 class="panel-title">Group Item #2</h3> 
    <div class="panel-body"> 
      Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты. Переписывается реторический за, щеке сбить, если большой языкового ему алфавит составитель силуэт меня страну рукопись языком вопроса толку оксмокс она. 
    </div> 
    <h3 class="panel-title">Group Item #3</h3> 
    <div class="panel-body"> 
      Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты. Переписывается реторический за, щеке сбить, если большой языкового ему алфавит составитель силуэт меня страну рукопись языком вопроса толку оксмокс она. 
    </div> 
  </div> 
</div>

Всем привет. Есть проблема одна, есть код аккордеона, сейчас он не работает, нужно чтобы если активен один блок, то кликая на другой блок тот блок который был активен закрывается а тот блок по которому кликнули должен открываться. Проблема тут в том что я не могу удалить класс всем предыдущим заголовкам у которых есть активный класс. В частности ошибка на 12 строке, я не много понимаю почему такая ошибка, но не пойму как ее решить. Надеюсь я понятно объяснил суть проблемы, у меня плохо получается расписывать вот так все)

Answer 1

var panelItem = document.querySelectorAll('.panel-title'), 
  bodyItem = document.querySelectorAll('.panel-body'); 
panelItem.__proto__.forEach = [].__proto__.forEach; 
 
var activePanel; 
panelItem.forEach(function(item, i, panelItem) { 
  item.addEventListener('click', function(e) { 
    //show new thingy; 
    this.classList.add('panel-active'); 
    this.nextElementSibling.classList.add('active'); 
    //hide old thingy 
    if (activePanel) { 
      activePanel.classList.remove('panel-active'); 
      activePanel.nextElementSibling.classList.remove('active'); 
    } 
    //update thingy 
    activePanel = (activePanel === this) ? 0 : this; 
  }); 
});
* { 
  padding: 0; 
  margin: 0; 
} 
.container { 
  max-width: 700px; 
  margin: 0 auto; 
  padding-top: 20px; 
} 
.panel { 
  margin-bottom: 5px; 
} 
.panel-title { 
  padding: 10px 15px; 
  background-color: #f5f5f5; 
  border: 1px solid #ddd; 
  font-size: 16px; 
  color: #333; 
  border-radius: 4px; 
  font-family: 'Helvetica'; 
  font-weight: 300; 
  cursor: pointer; 
  margin-bottom: 5px; 
} 
.panel-body { 
  padding: 15px; 
  border: 1px solid #ddd; 
  border-bottom-left-radius: 4px; 
  border-bottom-right-radius: 4px; 
  display: none; 
  margin-bottom: 10px; 
  background: #fff; 
} 
.panel-active { 
  margin-bottom: 0; 
  border-bottom: 0; 
  border-bottom-left-radius: 0; 
  border-bottom-right-radius: 0; 
  text-decoration: underline; 
} 
.active { 
  display: block; 
}
<div class="container"> 
  <div class="panel-group"> 
    <h3 class="panel-title">Group Item #1</h3> 
    <div class="panel-body"> 
      Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты. Переписывается реторический за, щеке сбить, если большой языкового ему алфавит составитель силуэт меня страну рукопись языком вопроса толку оксмокс она. 
    </div> 
    <h3 class="panel-title">Group Item #2</h3> 
    <div class="panel-body"> 
      Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты. Переписывается реторический за, щеке сбить, если большой языкового ему алфавит составитель силуэт меня страну рукопись языком вопроса толку оксмокс она. 
    </div> 
    <h3 class="panel-title">Group Item #3</h3> 
    <div class="panel-body"> 
      Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты. Переписывается реторический за, щеке сбить, если большой языкового ему алфавит составитель силуэт меня страну рукопись языком вопроса толку оксмокс она. 
    </div> 
  </div> 
</div>

Answer 2

Можно немного облегчить код, заменив класс .active для panel-body, на стиль .panel-active + .panel-body

А также, воспользовавшись тем, что функция getElementsByClassName возвращает живую коллекцию.

var panelItem = document.querySelectorAll('.panel-title'), 
  active = document.getElementsByClassName('panel-active'); 
 
Array.from(panelItem).forEach(function(item, i, panelItem) { 
  item.addEventListener('click', function(e) { 
    if (active.length > 0 && active[0] !== this) // если есть активный элемент, и это не тот по которому кликнули 
      active[0].classList.remove('panel-active'); // убрать класс panel-active 
 
    // изменить состояние класса panel-active на текущем элементе: добавить если не было, убрать если было. 
    this.classList.toggle('panel-active'); 
  }); 
});
* { 
  padding: 0; 
  margin: 0; 
} 
.container { 
  max-width: 700px; 
  margin: 0 auto; 
  padding-top: 20px; 
} 
.panel { 
  margin-bottom: 5px; 
} 
.panel-title { 
  padding: 10px 15px; 
  background-color: #f5f5f5; 
  border: 1px solid #ddd; 
  font-size: 16px; 
  color: #333; 
  border-radius: 4px; 
  font-family: 'Helvetica'; 
  font-weight: 300; 
  cursor: pointer; 
  margin-bottom: 5px; 
} 
.panel-body { 
  padding: 15px; 
  border: 1px solid #ddd; 
  border-bottom-left-radius: 4px; 
  border-bottom-right-radius: 4px; 
  display: none; 
  margin-bottom: 10px; 
  background: #fff; 
} 
.panel-active { 
  margin-bottom: 0; 
  border-bottom: 0; 
  border-bottom-left-radius: 0; 
  border-bottom-right-radius: 0; 
  text-decoration: underline; 
} 
.panel-active + .panel-body { 
  display: block; 
}
<div class="container"> 
  <div class="panel-group"> 
    <h3 class="panel-title">Group Item #1</h3> 
    <div class="panel-body"> 
      Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты. Переписывается реторический за, щеке сбить, если большой языкового ему алфавит составитель силуэт меня страну рукопись языком вопроса толку оксмокс она. 
    </div> 
    <h3 class="panel-title">Group Item #2</h3> 
    <div class="panel-body"> 
      Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты. Переписывается реторический за, щеке сбить, если большой языкового ему алфавит составитель силуэт меня страну рукопись языком вопроса толку оксмокс она. 
    </div> 
    <h3 class="panel-title">Group Item #3</h3> 
    <div class="panel-body"> 
      Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты. Переписывается реторический за, щеке сбить, если большой языкового ему алфавит составитель силуэт меня страну рукопись языком вопроса толку оксмокс она. 
    </div> 
  </div> 
</div>

Answer 3

Мой вариант

[].forEach.call(document.querySelectorAll('.panel-title'), function(item) { 
	item.addEventListener('click', function(e) { 
		display=(this.nextElementSibling.style.display=='block') ? 'none' : 'block'; 
		[].forEach.call(this.parentNode.querySelectorAll('.panel-body'), function(panels) { 
			panels.style.display='none'; 
		}); 
		this.nextElementSibling.style.display=display; 
	}); 
});
* { 
  padding: 0; 
  margin: 0; 
} 
.container { 
  max-width: 700px; 
  margin: 0 auto; 
  padding-top: 20px; 
} 
.panel { 
  margin-bottom: 5px; 
} 
.panel-title { 
  padding: 10px 15px; 
  background-color: #f5f5f5; 
  border: 1px solid #ddd; 
  font-size: 16px; 
  color: #333; 
  border-radius: 4px; 
  font-family: 'Helvetica'; 
  font-weight: 300; 
  cursor: pointer; 
  margin-bottom: 5px; 
} 
.panel-body { 
  padding: 15px; 
  border: 1px solid #ddd; 
  border-bottom-left-radius: 4px; 
  border-bottom-right-radius: 4px; 
  display: none; 
  margin-bottom: 10px; 
  background: #fff; 
} 
.panel-active { 
  margin-bottom: 0; 
  border-bottom: 0; 
  border-bottom-left-radius: 0; 
  border-bottom-right-radius: 0; 
  text-decoration: underline; 
} 
.panel-active + .panel-body { 
  display: block; 
}
<div class="container"> 
  <div class="panel-group"> 
    <h3 class="panel-title">Group Item #1</h3> 
    <div class="panel-body"> 
      Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты. Переписывается реторический за, щеке сбить, если большой языкового ему алфавит составитель силуэт меня страну рукопись языком вопроса толку оксмокс она. 
    </div> 
    <h3 class="panel-title">Group Item #2</h3> 
    <div class="panel-body"> 
      Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты. Переписывается реторический за, щеке сбить, если большой языкового ему алфавит составитель силуэт меня страну рукопись языком вопроса толку оксмокс она. 
    </div> 
    <h3 class="panel-title">Group Item #3</h3> 
    <div class="panel-body"> 
      Далеко-далеко за словесными горами в стране, гласных и согласных живут рыбные тексты. Переписывается реторический за, щеке сбить, если большой языкового ему алфавит составитель силуэт меня страну рукопись языком вопроса толку оксмокс она. 
    </div> 
  </div> 
</div>

READ ALSO
Проблема с кодировкой при Ajax-запросе

Проблема с кодировкой при Ajax-запросе

Всем добрый деньЕсть такой несложный код:

101
Как отрезать слово до запятой? 2 [дубликат]

Как отрезать слово до запятой? 2 [дубликат]

На данный вопрос уже ответили:

121
Vue.js, mocha+chai. Как протестировать action c запросом на стороннее АПИ

Vue.js, mocha+chai. Как протестировать action c запросом на стороннее АПИ

День добрыйМожет ли мне кто-нибудь подсказать, как протестировать асинхронный action в хранилище?

117
Передача данных в класс [дубликат]

Передача данных в класс [дубликат]

На данный вопрос уже ответили:

142