简体   繁体   中英

Why is my collapsible not working?

I'm having trouble getting this collapsible to work. It has something to do with the div, because on the 2nd collapsible, I removed the containing div and it works fine. What's the problem?

https://codepen.io/TheConnorCraig/pen/eLdaVQ

 var coll = document.getElementsByClassName("cbCollapse"); 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"; } }); } 
 .cbCollapseRow { display: flex; } .cbCollapse { background-image: url('https://www.pitsco.com/skins/mobile/PlusIcon.svg'); background-size: cover; cursor: pointer; padding: 30px; border: none; margin-bottom: 15px; } .content { width: 100%; padding: 0 18px; max-height: 0; overflow: hidden; transition: max-height 0.2s ease-out; background-color: #f1f1f1; } 
 <div class="cbCollapseRow"> <button class="cbCollapse"></button> <h2>Sample 1</h2> </div> <div class="content"> <p>Lorem ipsum dolor sit amet</p> </div> <button class="cbCollapse"></button> <div class="content"> <p>Lorem ipsum dolor sit amet</p> </div> <div class="cbCollapseRow"> <button class="cbCollapse"></button> <h2>Sample 3</h2> </div> <div class="content"> <p>Lorem ipsum dolor sit amet</p> </div> 

You are targeting nextElementSibling in your code, so you need to move your button html just above the div you want to collapse / expand.

For example (messes up the alignment you probably want for your h2 tags but illustrates the issue):

 var coll = document.getElementsByClassName("cbCollapse"); 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"; } }); } 
 .cbCollapseRow { display: flex; } .cbCollapse { background-image: url('https://www.pitsco.com/skins/mobile/PlusIcon.svg'); background-size: cover; cursor: pointer; padding: 30px; border: none; margin-bottom: 15px; } .content { width: 100%; padding: 0 18px; max-height: 0; overflow: hidden; transition: max-height 0.2s ease-out; background-color: #f1f1f1; } 
 <div class="cbCollapseRow"> <h2>Sample 1</h2> </div> <button class="cbCollapse"></button> <div class="content"> <p>Lorem ipsum dolor sit amet</p> </div> <button class="cbCollapse"></button> <div class="content"> <p>Lorem ipsum dolor sit amet</p> </div> <div class="cbCollapseRow"> <h2>Sample 3</h2> </div> <button class="cbCollapse"></button> <div class="content"> <p>Lorem ipsum dolor sit amet</p> </div> 

The reason your element is not expanding with the containing div is due to the nextElementSibling() you are targeting. This is causing your <h2> to receive the max-height styling.

If you want to keep the container on all of them, you can change it to this.parentNode.nextElementSibling; and the current code will work. see this pen

This will however break the div that is not wrapped. If you wanted to wrap them all though, this should not be an issue.

nextElementSibling should speak by itself. It's not a sibling in your case.

Also, try not to create/assign functions inside for loops.
Here's a remake using the data-* attribute to target desired Content elements ID

 const collapseTarget = (evt) => { const btn = evt.currentTarget; const id = btn.getAttribute("data-collapse"); const cont = document.querySelector(id); btn.classList.toggle("active"); cont.style.maxHeight = cont.clientHeight ? 0 : cont.scrollHeight + "px"; } const collapseBtns = document.querySelectorAll("[data-collapse]"); [...collapseBtns].forEach( btn => btn.addEventListener("click", collapseTarget )); 
 .cbCollapseRow { display: flex; } .cbCollapse { background-image: url('https://www.pitsco.com/skins/mobile/PlusIcon.svg'); background-size: cover; cursor: pointer; padding: 30px; border: none; margin-bottom: 15px; } .content { padding: 0 18px; max-height: 0; overflow: hidden; transition: max-height 0.2s ease-out; background-color: #f1f1f1; } 
 <div class="cbCollapseRow" data-collapse="#coll1"> <button class="cbCollapse"></button> <h2>Sample 1</h2> </div> <div class="content" id="coll1"> <p>Lorem ipsum dolor sit amet</p> </div> <button class="cbCollapse" data-collapse="#coll2"></button> <div class="content" id="coll2"> <p>Lorem ipsum dolor sit amet</p> </div> <div class="cbCollapseRow" data-collapse="#coll3"> <button class="cbCollapse"></button> <h2>Sample 3</h2> </div> <div class="content" id="coll3"> <p>Lorem ipsum dolor sit amet</p> </div> 

var content = this.nextElementSibling;

This means that the element you're trying to collapse/uncollapse is the direct neighbor of the button, which in the case of the first and last elements, is the h2 tag. Change it to

var content = this.parentNode.nextElementSibling; and the correct div will be targeted.

Here's the working snippet:

 var coll = document.getElementsByClassName("cbCollapse"); var i; for (i = 0; i < coll.length; i++) { coll[i].addEventListener("click", function() { this.classList.toggle("active"); //This is the changed line VVVVV var content = this.parentNode.nextElementSibling; if (content.style.maxHeight) { content.style.maxHeight = null; } else { content.style.maxHeight = content.scrollHeight + "px"; } }); } 
 .cbCollapseRow { display: flex; } .cbCollapse { background-image: url('https://www.pitsco.com/skins/mobile/PlusIcon.svg'); background-size: cover; cursor: pointer; padding: 30px; border: none; margin-bottom: 15px; } .content { width: 100%; padding: 0 18px; max-height: 0; overflow: hidden; transition: max-height 0.2s ease-out; background-color: #f1f1f1; } 
 <div class="cbCollapseRow"> <button class="cbCollapse"></button> <h2>Sample 1</h2> </div> <div class="content"> <p>Lorem ipsum dolor sit amet</p> </div> <div class="cbCollapseRow"> <button class="cbCollapse"></button> <h2>Sample 2</h2> </div> <div class="content"> <p>Lorem ipsum dolor sit amet</p> </div> <div class="cbCollapseRow"> <button class="cbCollapse"></button> <h2>Sample 3</h2> </div> <div class="content"> <p>Lorem ipsum dolor sit amet</p> </div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM