创建多个手风琴 html/Javascript/CSS

Creating Multiple Accordions html/Javascript/CSS

我正在尝试制作嵌套手风琴(展开一个,然后在内部展开另一个),但由于某种原因,内部手风琴不起作用。

这是基于 w3 school 的手风琴代码,但我用图像替换了按钮。我的逻辑是,如果我复制粘贴第一个 accordion 并将其重命名为“accordion 1”,我可以稍后调用 accordion1 并且会发生与原始 accordion 相同的事情。

但是当我点击内部手风琴按钮时,没有任何反应。我不太确定为什么会这样,因为它似乎是直接复制粘贴。我不确定这里是否需要做一些不同的事情

var acc = document.getElementsByClassName("accordion");
var i;

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

var acc1 = document.getElementsByClassName("accordion1");
var i;

for (i = 0; i < acc1.length; i++) {
  acc1[i].addEventListener("click", function() {
    this.classList.toggle("active");
    var panel = this.nextElementSibling;
    if (panel.style.maxHeight) {
      panel.style.maxHeight = null;
    } else {
      panel.style.maxHeight = panel.scrollHeight + "px";
    }
  });
}
.accordion {
  background-image: url(https://i.imgur.com/Jqsaukf.png);
  background-repeat: no-repeat;
  background-position: 50% 50%;
  /* put the height and width of your image here */
  height: 50px;
  width: 200px;
  border: none;
  background-color: #eee;
  color: #444;
  cursor: pointer;
  padding: 18px;
  width: 100%;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
  transition: 0.4s;
}

.active,
.accordion:hover {
  background-color: #ccc;
}

.accordion:after {
  content: '[=12=]2B';
  color: #777;
  font-weight: bold;
  float: right;
  margin-left: 5px;
}

.active:after {
  content: "12";
}

.accordion1 {
  background-image: url(https://i.imgur.com/VXlZ0Ja.png);
  background-repeat: no-repeat;
  background-position: 50% 50%;
  /* put the height and width of your image here */
  height: 500px;
  width: 200px;
  border: none;
  background-color: #eee;
  color: #444;
  cursor: pointer;
  padding: 18px;
  width: 100%;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
  transition: 0.4s;
}

.active1,
.accordion1:hover {
  background-color: #ccc;
}

.accordion1:after {
  content: '[=12=]2B';
  color: #777;
  font-weight: bold;
  float: right;
  margin-left: 5px;
}

.active1:after {
  content: "12";
}

.panel {
  padding: 0 18px;
  background-color: white;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
}
<h2>Accordion with symbols</h2>
<p>In this example we have added a "plus" sign to each button. When the user clicks on the button, the "plus" sign is replaced with a "minus" sign.</p>

<button class="accordion"></button>
<div class="panel">
  <button class="accordion1"></button>
  <div class="panel1">
    <p>Lorem ipsum dolor sit amet</p>
  </div>
</div>
<br>
<button class="accordion"></button>
<div class="panel">
  <p><img src="https://i.imgur.com/Jqsaukf.png" alt="Italian Trulli"></p>
</div>

<button class="accordion"></button>
<div class="panel">
  <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>

编辑:我更改了我混淆的变量名;即 panel 和 panel1 以及 active 和 active 1 并且它有效,但我仍然想知道是否有更多 concise/efficient 方法来做到这一点。

我想要有 10 个以上的手风琴,它们带有不同的图像作为按钮,所以如果没有某种方法来压缩它,这个模块将最终变得疯狂。也许是一个 for 循环来替换手风琴数组中的每个图像?不确定 html/javascript/css.

是否有意义或什至可能

我举了这个例子来说明如何做到这一点。最主要的是循环概念以及如何使 HTML 对 adding/deleting 多个手风琴元素保持简单。想嵌套多少就嵌套多少。

备注: 将 .accordion 元素命名为 .accordion-tab 会更有意义。我没有做太多 CSS 造型,只是为了举例。在 Javascript 中,我展示了如何提取图像属性并随心所欲地使用它。您可能可以更好、更高效地编写很多这样的代码,但我试图使其快速且易于人类阅读。

如果您需要任何帮助,请告诉我。上帝保佑!

const acc = document.querySelectorAll(".accordion"); // Get all accordion tab elements
let i;
for (i = 0; i < acc.length; i++) {
    const accordion = acc[i];
    accordion.setAttribute('data-index', i);

    // Add content
    const content = accordion.getAttribute('data-content'); // Getting the accordion tab content
    const accordionContent = document.createElement("div"); // Create content element
    accordionContent.classList.add("accordion-content"); //Add content class
    accordionContent.innerHTML += content; // Add HTML
    accordion.prepend(accordionContent) // Add to DOM, if you want the nested accordions before the content, you can use append instead of prepend


    // Accordion button
    const imageData = accordion.getAttribute('data-image') ? accordion.getAttribute('data-image').split('|') : false; // Get image and alt text then split it by the | character in the attribute
    const button = document.createElement("button"); // Create a button
    button.classList.add("accordion-button"); // Add button class
    button.style.backgroundImage = "url('" + imageData[0] + "')"; // Add background image, you could instead create an image element and add the imageData[0] to the src, but you'd probably need to create your images at the perfect size or add and extract the dimensions in the data-image attribute. Ex: data-image="image1.png|Alt text for image|100px,100px"

    button.setAttribute('aria-label', imageData[1]); // Add image alt text
    accordion.prepend(button); // Add to DOM
    button.onclick = function() {
        togglePanel(accordion); // Add button click function, function is below in the code
    }

}

function togglePanel(accordion) {
    const button = accordion.querySelector('.accordion-button')
    const accordionContent = accordion.querySelector('.accordion-content')
    
    // Handle toggling here. I suggest set CSS styles, but you could use javascript to slide it
    accordion.classList.toggle('active');

};
/* I used display none and block just for the example. You can do the height transition with CSS or Javascript */ 
.accordion .accordion,
.accordion .accordion-content {
    display: none;
}

.accordion.active>.accordion,
.accordion.active>.accordion-content {
    display: block;
}



/* Just for example styling*/
button {
  cursor: pointer;
  height: 50px;
  width: 100%;
}
button:after {
  content: '+'
}
.accordion.active > button:after {
  content: '-'
}
.accordion-content {
    padding: 20px;
  width: 100%;
}

.accordion .accordion {
  margin-left: 20px;
}
.accordion.active > button {
  background: #4169e1;
 }
.accordion .accordion.active > button {
  background: #a1caf1;
 }
 
 .accordion .accordion .accordion.active > button {
  background: #a4dded;
 }
<!-- Main accordion -->
<div class="accordion"
   data-image="image1.png|Alt text for image"
   data-content="Accordion 1 text"
   >
   <!-- Nested accordion -->
   <div class="accordion"
      data-image="image2.png|Alt text for image"
      data-content="Nested accordion 1 content. Image should show below: <img src=&quot;https://media.swncdn.com/via/11580-mount-zion-bst.jpg&quot; width=&quot;300&quot;>"
      ></div>
</div>


<div class="accordion"
   data-image="image2.png|Alt text for image"
   data-content="Accordion 2 text"
   >
   <!-- Nested accordion -->
   <div class="accordion"
      data-image="image2.png|Alt text for image"
      data-content="Nested accordion 2 text"
      ></div>
</div>

<div class="accordion"
   data-image="image3.png|Alt text for image"
   data-content="Accordion 3 has no nested accordion"
   >
</div>

<div class="accordion"
   data-image="image2.png|Alt text for image"
   data-content="Accordion 2 text"
   >
   <!-- Nested accordion -->
   <div class="accordion"
      data-image="image2a.png|Alt text for image"
      data-content="Nested accordion 2 text"
      >
    </div>
   <!-- Another nested accordion -->
   <div class="accordion"
      data-image="image2a.png|Alt text for image"
      data-content="Another nested accordion 2 text"
      >
         <!-- Double nested accordion -->
   <div class="accordion"
      data-image="image2b.png|Alt text for image"
      data-content="Double nested accordion 2 text"
      ></div>
      
      </div>
</div>