问题
I'm trying to achieve a webpage with each h2 acting as items of an accordion. When clicked, the contents under the heading should expand (after being hidden).
I've been through a bunch of tutorials, but they usually use specific html (using links or buttons) but my html is exported from a markup language (orgmode) so can't be customised this way (at least I'd prefer not to). I haven't been able to modify any of them to suit my needs.
I'm not sure if the best solution would use css or javascript, or both. Here is the html body:
<div id="content">
<h1 class="title">Recipes</h1>
<div id="outline-container-org233deb6" class="outline-2">
<h2 id="org233deb6">Tea</h2>
<div class="outline-text-2" id="text-org233deb6">
</div>
<div id="outline-container-orgfbba0f7" class="outline-3">
<h3 id="orgfbba0f7">Ingredients</h3>
<div class="outline-text-3" id="text-orgfbba0f7">
<ul class="org-ul">
<li>1 tbsp tea leaves</li>
<li>1 cup water</li>
</ul>
</div>
</div>
<div id="outline-container-orgcc98fa7" class="outline-3">
<h3 id="orgcc98fa7">Instructions</h3>
<div class="outline-text-3" id="text-orgcc98fa7">
<ol class="org-ol">
<li>Boil some water</li>
<li>Put in tea leaves</li>
<li>Strain</li>
</ol>
</div>
</div>
</div>
</div>
From what I can tell, I'm trying to hide/show the outline-3
class upon clicking the h2 in outline-2
.
回答1:
Since you can't control the markup, this is how you can solve this:
const headerH2 = document.querySelectorAll('#content h2'); // first we put all wanted headers on variable
const outlinContent = document.querySelectorAll("div[class^=outline]"); // you can use regex to catch all div begining with 'outline-'
outlinContent.forEach(function(item){ if (item.id !== 'outline-container-org233deb6') { item.classList.add('hide'); } }); // hide them, skipping the one contain the trigger
headerH2[0].addEventListener('click', function() { // adding click listener to the first (or the only one in this example
outlinContent.forEach(function(item){ if (item.id !== 'outline-container-org233deb6') {item.classList.toggle('hide'); } }); // toggle content display
});
.hide {display: none;}
<div id="content">
<h1 class="title">Recipes</h1>
<div id="outline-container-org233deb6" class="outline-2">
<h2 id="org233deb6">Tea</h2>
<div class="outline-text-2" id="text-org233deb6">CONTENT</div>
<div id="outline-container-orgfbba0f7" class="outline-3">
<h3 id="orgfbba0f7">Ingredients</h3>
<div class="outline-text-3" id="text-orgfbba0f7">
<ul class="org-ul">
<li>1 tbsp tea leaves</li>
<li>1 cup water</li>
</ul>
</div>
</div>
<div id="outline-container-orgcc98fa7" class="outline-3">
<h3 id="orgcc98fa7">Instructions</h3>
<div class="outline-text-3" id="text-orgcc98fa7">
<ol class="org-ol">
<li>Boil some water</li>
<li>Put in tea leaves</li>
<li>Strain</li>
</ol>
</div>
</div>
</div>
</div>
Making content collapsible:
Note: in this example i use h2
for the trigger and sibling div
to hold the content.
const headerH2 = document.querySelectorAll('#content h2'); // first we put all wanted headers on variable
for (let i=0; i < headerH2.length; i++) { // you can use the modarn forEach, but this is much faster
let nextDiv = headerH2[i].nextElementSibling; // this is how you select the next element after the header
nextDiv.classList.add('hide'); // we hide all of them by default
headerH2[i].addEventListener('click', function() { // now we are adding click listener:
if (document.querySelector('#content div:not(.hide)')) {document.querySelector('#content div:not(.hide)').classList.add('hide')}; // this will close other open content divs if they exist
nextDiv.classList.remove('hide'); // this will show the right content when click
});
}
.hide {display: none;}
<div id="content">
<h2>TITLE 1</h2>
<div>CONTENT 1</div>
<h2>TITLE 2</h2>
<div>CONTENT 2</div>
<h2>TITLE 3</h2>
<div>CONTENT 3</div>
<h2>TITLE 4</h2>
<div>CONTENT 4</div>
<h2>TITLE 5</h2>
<div>CONTENT 5</div>
<h2>TITLE 6</h2>
<div>CONTENT 6</div>
</div>
For a side note, html5 has the [details]
element that create a disclosure widget in which information is visible only when the widget is toggled into an "open" state, and should be using here in order to get the semantic and SEO etc...
Some helpful MDN links where you can learn much more:
querySelectorAll
nextElementSibling
:not selector
Hope that solved your problem and help others with similar question. Enjoy Code!
来源:https://stackoverflow.com/questions/59440201/collapsible-headings-accordion-from-markup-exported-html