Невозможно иметь вложенные складные элементы, правильно отображающие их содержимое, когда дети раскрываются - PullRequest
0 голосов
/ 18 июня 2020

Начиная с кода, найденного в https://www.w3schools.com/howto/howto_js_collapsible.asp, я хотел бы создать сворачиваемое меню, которое также работало бы для вложенного содержимого.

var coll = document.getElementsByClassName("collapsible");
var i;

for (i = 0; i < coll.length; i++) {
  coll[i].addEventListener("click", function() {
    this.classList.toggle("active");
    var content = this.nextElementSibling;
    if (content.style.maxHeight){
      content.style.maxHeight = null;
    } else {
      content.style.maxHeight = content.scrollHeight + "px";
    } 
  });
}
.collapsible {
  background-color: #777;
  color: white;
  cursor: pointer;
  padding: 18px;
  width: 100%;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
}

.active, .collapsible:hover {
  background-color: #555;
}

.collapsible:after {
  content: '\002B';
  color: white;
  font-weight: bold;
  float: right;
  margin-left: 5px;
}

.active:after {
  content: "\2212";
}

.content {
  padding: 0 18px;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
  background-color: #f1f1f1;
}
<button class="collapsible">Open Collapsible</button>
<div class="content">
<button class="collapsible">Open Collapsible</button>
<div class="content">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
<button class="collapsible">Open Collapsible</button>
<div class="content">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
</div>

Приведенный выше код работает для первого (root) сворачиваемого объекта.

Однако, когда дочерний сворачиваемый объект раскрывается, недостаточно места для просмотра их содержимого.

Только если они остаются открытыми, закрытие root сворачиваемого объекта и его повторное открытие покажет дочерний контент правильно.

Я знаю, что проблема в в том, что, когда складной элемент root раскрывается, его содержимое maxHeight устанавливается на scrollHeight + "px";, и это будет высота дочернего элемента, который все еще закрыт.

Как я могу сделать maxHeight сворачиваемых элементов динамически изменяются при расширении их дочерних элементов?

1 Ответ

1 голос
/ 18 июня 2020

Вы должны проверить и изменить максимальную высоту для элементов при открытии и закрытии дочерних элементов (частичный код).

for (i = 0; i < coll.length; i++) {
  coll[i].addEventListener("click", function() {
    this.classList.toggle("active");
    var content = this.nextElementSibling;
    if (content.style.maxHeight){
      content.style.maxHeight = null;
    } else {
      content.style.maxHeight = content.scrollHeight + "px";
    }
    // from last to first to recalculate parent height after child
    for (var j = coll.length - 1; j >= 0;  j--) {
      if (coll[j].classList.contains('active')) {
        console.log(j, coll[j].classList);
        var c2 = coll[j].nextElementSibling;
        console.log(c2);
        c2.style.maxHeight = null;
        c2.style.maxHeight = c2.scrollHeight + "px";
      }
    }
  });
}

Но приведенный выше код будет работать, если переход css отключен (потому что js триггеры непосредственно перед завершением перехода).

Итак, если переход необходим, вы можете добавить тайм-аут для проверки изменений после его завершения. Примерно так:

var coll = document.getElementsByClassName("collapsible");
var i;

var checkCollapsible = function() {
  for (var j = coll.length - 1; j >= 0;  j--) {
      if (coll[j].classList.contains('active')) {
        console.log(j, coll[j].classList);
        var c2 = coll[j].nextElementSibling;
        console.log(c2);
        c2.style.maxHeight = null;
        c2.style.maxHeight = c2.scrollHeight + "px";
      }
    }
};

for (i = 0; i < coll.length; i++) {
  coll[i].addEventListener("click", function() {
    this.classList.toggle("active");
    var content = this.nextElementSibling;
    if (content.style.maxHeight){
      content.style.maxHeight = null;
    } else {
      content.style.maxHeight = content.scrollHeight + "px";
    } 
    window.setTimeout(checkCollapsible, 200);
  });
}

https://jsfiddle.net/6yn0mewz/3/

Также доступна куча событий перехода. Итак, для webkit вы можете использовать что-то вроде (частичный код)

for (i = 0; i < coll.length; i++) {
  coll[i].addEventListener("click", function() {
    this.classList.toggle("active");
    var content = this.nextElementSibling;
    if (content.style.maxHeight){
      content.style.maxHeight = null;
    } else {
      content.style.maxHeight = content.scrollHeight + "px";
    }
   content.addEventListener('webkitTransitionEnd', checkCollapsible);
  });
}

https://jsfiddle.net/6yn0mewz/4/

См. события перехода CSS3 и Событие TransitionEnd не запускается? Например, .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...