简体   繁体   English

创建一个用于扩展和折叠手风琴的切换按钮

[英]Creating a toggle button for expanding and collapsing an Accordion

I created a modified accordion for a FAQ page I am working on from a W3Schools example. 我从W3Schools示例中为我正在处理的FAQ页面创建了修改后的手风琴。 I am new to Javascript and I am in need of a bit of help. 我是Java语言的新手,我需要一些帮助。 I wanted to build a button that would toggle between expanding all of the panels and closing all the panels. 我想建立一个在展开所有面板和关闭所有面板之间切换的按钮。 I was able to get some help from another blog post that someone had written to create a close all panels button but now I would like to build a function that will toggle between closing all and opening all. 我可以从另一个人写的创建“关闭所有面板”按钮的博客文章中获得一些帮助,但是现在我想构建一个函数,该功能可以在“全部关闭”和“全部打开”之间切换。 I am also looking to have all of this inline so that I can embed this one page of code into another page. 我还希望将所有这些都内联,以便可以将这一页代码嵌入另一页。 I have attached the code that I have created so far. 我已经附加了到目前为止创建的代码。

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
.accordion {
    background-color: none;
    cursor: pointer;
    padding: 30px;
    width: 100%;
    border: #DADCE0;
    border-style: solid;
    border-width: 1px 0px 0px 0px;
    text-align: left;
    outline: none;
    font-family: Google Sans, sans-serif;
    font-weight: medium;
    font-size: 18px;
    line-height: 30px;
    transition: 0.4s;
    color: #1A73E8;
}

.accordion:hover {
    color: #174EA6;
}

.active {
    color: #174EA6;
    border-top-color: #DADCE0;
    border-bottom-color: #174EA6;
    border-style: solid;
    border-width: 1px 0px 2px 0px;
}

.accordion:after {
    font-family: 'Material Icons';
    content: "keyboard_arrow_down"; /*Google keyboard arrow down*/
    font-weight: bold;
    font-size: 24px;
    float: right;
    margin-left: 5px;
}

.active:after {
  font-family: 'Material Icons';
  content: "keyboard_arrow_up"; /*Google keyboard arrow up*/
  font-weight: bold;
  font-size: 24px;
  float: right;
  margin-left: 5px;
}

.panel {
    padding: 0px 18px;
    background-color: white;
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.4s ease-out;
}

.closeall {
    float: right;
    margin: 1% 2% 0 0;
    cursor: pointer;
}

body {
    font-family: Roboto Light, sans-serif;
    line-height: 26px;
    font-size: 16px;
    color: #202124;
}

a {
    color: #4285f4;
}

</style>
</head>
<body>

<button  class="closeall" onclick="collapseall()">Close all</button>

<button class="accordion">Can I host my own events?</button>
<div class="panel">
  <p>Of course you can!</p>
</div>

<button class="accordion">Are the events for students?</button>
<div class="panel">
  <p>Yes, please see here.</p>
</div>

<button class="accordion">Are the events for teachers?</button>
<div class="panel">
  <p>Yes, please see here.</p>
</div>

<button class="accordion">Are the events for teachers 2?</button>
<div class="panel">
  <p>Yes, please see here 2.</p>
</div>

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

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

function collapseall() {  //problematic part
    var x = document.getElementsByClassName("panel");
    var b;
    for (b = 0; b < x.length; b++) {
        x[b].style.maxHeight = null;
        x[b].previousElementSibling.classList.remove('active');
  }
}
</script>

</body>
</html>
function collapseall() {
    var x = document.getElementsByClassName("accordion");
    var y = 0;
    var b;

    for (b = 0; b < x.length; b++) {
       if(x[b].classList.contains('active'))y++;
    }

    if(x.length==y||y==0){
      for (b = 0; b < x.length; b++) {
         x[b].dispatchEvent(new Event('click'));
      }
    }else{
      for (b = 0; b < x.length; b++) {
         if(x[b].classList.contains('active'))
            x[b].dispatchEvent(new Event('click'));
      }
    }
}

Good news is you're very close to a proper solution, which I implemented here for you. 好消息是您正在接近一个适当的解决方案, 我在这里为您实施了该解决方案。 Short way to achieve that would might look like 实现该目标的捷径可能看起来像

// Single reference to all panels 
// Getting them each time is heavy for the browser
var x = document.getElementsByClassName("panel");

// Indicator if we should open or close all panels
var isToggledOff = true;

Then you need two very similar functions to open or collapse all panels 然后,您需要两个非常相似的功能来打开或折叠所有面板

function collapseAll() { 
    for (var b = 0; b < x.length; b++) {
        x[b].style.maxHeight = null;
        x[b].previousElementSibling.classList.remove('active');
  }
}

function expandAll() {
    for (var b = 0; b < x.length; b++) {
        x[b].style.maxHeight = "58px";
        x[b].previousElementSibling.classList.add('active');
   }
}

Last but not least you need logic that will decide if we want to open or close all panels and what to do with them in the future 最后但并非最不重要的一点是,您需要逻辑来决定我们是否要打开或关闭所有面板以及将来如何处理它们

function toggle() {
   if (isToggledOff) this.expandAll();
   else this.collapseAll();
   isToggledOff = !isToggledOff
}

Additional things you might want to consider 您可能需要考虑的其他事项

  1. Why do you need to set that maxHeight? 为什么需要设置该maxHeight? Wouldn't it be easier to add it to active CSS class? 将其添加到活动CSS类会更容易吗?
  2. Functional programming in JS gives you super powers, why wouldn't you use .forEach() method instead of for loop? JS中的函数式编程具有超强的功能,为什么不使用.forEach()方法代替for循环? It might be tricky but worthy lesson :) 这可能很棘手,但值得一课:)
  3. Why do you need previousElementSibling property? 为什么需要previousElementSibling属性?
  4. Next time you add a question try to provide people helping you with minimal example, so that they can easier understand what's the problem. 下次您添加问题时,请尝试为人们提供最少的帮助,以使他们可以更轻松地了解问题所在。 In this case you could strip css code from your example :) 在这种情况下,您可以从示例中剥离CSS代码:)

Alternative way 替代方式

var x = Array.from(document.getElementsByClassName("panel"));
var isToggledOff = true;
function toggle() {
    x.forEach(el => el
        .previousElementSibling
        .classList
        [isToggledOff ? "add" : "remove"]('active')
    )
   isToggledOff = !isToggledOff
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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