【问题标题】:Creating a toggle button for expanding and collapsing an Accordion创建用于展开和折叠 Accordion 的切换按钮
【发布时间】:2018-08-23 23:51:19
【问题描述】:

我根据 W3Schools 示例为我正在处理的 FAQ 页面创建了一个修改后的手风琴。我是 Javascript 新手,需要一些帮助。我想构建一个按钮,可以在展开所有面板和关闭所有面板之间切换。我能够从另一篇博客文章中获得一些帮助,该文章有人为创建关闭所有面板按钮而编写,但现在我想构建一个在关闭所有面板和打开所有面板之间切换的功能。我还希望将所有这些内联,以便我可以将这一页代码嵌入到另一页中。我已经附上了我到目前为止创建的代码。

<!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>

【问题讨论】:

    标签: javascript jquery html css accordion


    【解决方案1】:
    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'));
          }
        }
    }
    

    【讨论】:

      【解决方案2】:

      好消息是您非常接近合适的解决方案,which I implemented here 适合您。实现这一目标的捷径可能看起来像

      // 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;
      

      那么你需要两个非常相似的函数来打开或折叠所有面板

      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');
         }
      }
      

      最后但并非最不重要的一点是,您需要逻辑来决定我们是要打开还是关闭所有面板以及将来如何处理它们

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

      您可能需要考虑的其他事项

      1. 为什么需要设置 maxHeight?将它添加到活动的 CSS 类中不是更容易吗?
      2. JS 中的函数式编程赋予了你超能力,为什么不使用 .forEach() 方法而不是 for 循环呢?这可能很棘手但值得一课:)
      3. 为什么需要 previousElementSibling 属性?
      4. 下次添加问题时,请尝试为帮助您的人提供最少的示例,以便他们更容易理解问题所在。在这种情况下,您可以从示例中删除 css 代码:)

      另一种方式

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-03
        • 2014-03-12
        • 2017-06-15
        • 2013-09-07
        • 2020-08-21
        • 1970-01-01
        • 2013-09-20
        • 1970-01-01
        相关资源
        最近更新 更多