Vanilla Javascript手风琴功能

时间:2018-05-31 02:10:06

标签: javascript accordion

在我打开其他面板上的点击后,我需要帮助关闭其他面板。在过去的一周里,我一直试图绕过它,但我无法做到。

我不想使用jquery库,我希望能够将此代码直接编码到我的网站中。

我认为所需的javascript代码在概念上很简单,但很难为像我这样的人写。我仍然不完全理解javascript命令,函数等是如何工作的。

非常感谢任何帮助或指导!

这是我的代码:

HTML

    <!DOCTYPE html>
      <html>
      <head>
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="stylesheet" href="accordion.css">
      </head>
      <body>

         <h3 class="accordion">Basics of Sailing</h3>
          <div class="panel">
           <div class="col col-4 middle">
            <!-- <div class="space"></div> -->
             <h4>Before Choosing a Sailboat</h4>
             <p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
      </div>
      <div class="col col-4 middle">
        <!-- <div class="space"></div> -->
        <h4>Car Topping & Trailing</h4>
        <p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
      </div>
      <div class="col col-4 middle">
        <!-- <div class="space"></div> -->
        <h4>Safety Equipment</h4>
        <p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
      </div>
    </div>
    <h3 class="accordion">Basics of Sailing</h3>
    <div class="panel">
      <div class="col col-4 middle">
        <!-- <div class="space"></div> -->
        <h4>Before Choosing a Sailboat</h4>
        <p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
        </div>
        <div class="col col-4 middle">
          <!-- <div class="space"></div> -->
           <h4>Car Topping & Trailing</h4>
          <p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
            </div>
          <div class="col col-4 middle">
           <!-- <div class="space"></div> -->
           <h4>Safety Equipment</h4>
           <p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
          </div>
         </div>

       <script src="accordion.js"></script>

      </body>
     </html>

CSS

    .accordion {
        background-color: #2364aa;
        color: #ffffff;
        cursor: pointer;
        padding: 18px;
        border: none;
        text-align: left;
        outline: none;
        font-size: 21px;
        transition: 0.4s;
    }

     .open, .accordion:hover {
        background-color: #205A99;
    }

     .accordion:after {
       content: '\f067';
       font-family: "Font Awesome 5 Free";
       color: #ffffff;
       float: right;
       font-size: 1.25em;
       line-height: 25px;
    }

     .open:after {
       content: "\2212";
    }

     .panel {
       max-height: 0;
       overflow: hidden;
       transition: 0.2s ease-out;
    }

    .panel-body {
       padding: 18px 0;
    }

    @media only screen and (min-width: 960px) {
     .container {
       display: table;
       box-sizing: border-box;
   }
     .row .col {
       margin: 10px 0;
   }
     .col {
       display: table-cell;
   }
     .col.middle {
       vertical-align: middle;
   }
     .col-2 {
       width: 50%;
       padding-right: 72px;
   }
     .col-4 {
       width: 33.33333333333333333%;
       padding-right: 72px;
   }
  }

的Javascript

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

3 个答案:

答案 0 :(得分:1)

Event Delegation

  1. 将所有内容包装在一个块元素中。

    var main = document.querySelector(`main`)
    
  2. 将EventListener添加到该“父”元素

    main.addEventListener('click', ....
    
  3. 现在,如果main 点击main的任何后代,则会调用回调函数。因此,我们只有一个EventListener代表每个.accordion监听点击事件。我们使用.accordion条件和 event.target 属性确定实际点击的if

  4. mutual exclusivity的规则适用于手风琴的工作原理:

    • 只有一个.accordion + .panel组合可以拥有.active类。

    • 每当需要更改时(在这种情况下,点击e.target(点击的元素), 所有.accordion s 将删除.active类(无论它们是否实际拥有它)。

    • 在没有.active类的元素后,您将其提交给e.target

  5. 更改

    • .accordion + .panel.active代替.accordion.active

    • .style.maxHeight已被班级.active取代:

      .panel.active {
        max-height: 2000px;
        height:auto;
        overflow: hidden;
        transition: 0.2s ease-out;
      }
      

    演示

    详细信息在演示中进行了评论

    // Reference the parent of all .accordion
    var main = document.querySelector('main');
    
    /* Register main to click events...
    || when main or any of its descendant elements are clicked...
    */
    main.addEventListener("click", function(e) {
    
      /* Collect all .accordion into a NodeList and convert it into
      || an array.
      */
      var acc = Array.from(document.querySelectorAll(".accordion"));
      
      /* Loop thru each .accordion  to remove the .active class
      || from each .panel
      */
      for (let a = 0; a < acc.length; a++) {
        var panel = acc[a].nextElementSibling;
        panel.classList.remove('active');
      }
      /* After nothing has class .active, assign .active to the
      || .panel of the clicked element (e.target)
      */
      if (e.target !== e.currentTarget) {
        var tgt = e.target.nextElementSibling;
        tgt.classList.add("active");
      }
    });
    .accordion {
      background-color: #2364aa;
      color: #ffffff;
      cursor: pointer;
      padding: 18px;
      border: none;
      text-align: left;
      outline: none;
      font-size: 21px;
      transition: 0.4s;
    }
    
    .open,
    .accordion:hover {
      background-color: #205A99;
    }
    
    .accordion:after {
      content: '\f067';
      font-family: "Font Awesome 5 Free";
      color: #ffffff;
      float: right;
      font-size: 1.25em;
      line-height: 25px;
    }
    
    .open:after {
      content: "\2212";
    }
    
    .panel {
      max-height: 0;
      overflow: hidden;
      transition: 0.2s ease-out;
    }
    
    .panel.active {
      max-height: 2000px;
      height:auto;
      overflow: hidden;
      transition: 0.2s ease-out;
    }
    
    @media only screen and (min-width: 960px) {
      .container {
        display: table;
        box-sizing: border-box;
      }
      .row .col {
        margin: 10px 0;
      }
      .col {
        display: table-cell;
      }
      .col.middle {
        vertical-align: middle;
      }
      .col-2 {
        width: 50%;
        padding-right: 72px;
      }
      .col-4 {
        width: 33.33333333333333333%;
        padding-right: 72px;
      }
    }
    <!DOCTYPE html>
    <html>
    
    <head>
      <meta name="viewport" content="width=device-width, initial-scale=1">
    
    </head>
    
    <body>
      <main>
        <h3 class="accordion">Basics of Sailing</h3>
        <div class="panel">
          <div class="col col-4 middle">
            <!-- <div class="space"></div> -->
            <h4>Before Choosing a Sailboat</h4>
            <p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
          </div>
          <div class="col col-4 middle">
            <!-- <div class="space"></div> -->
            <h4>Car Topping &amp; Trailing</h4>
            <p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
          </div>
          <div class="col col-4 middle">
            <!-- <div class="space"></div> -->
            <h4>Safety Equipment</h4>
            <p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
          </div>
        </div>
        <h3 class="accordion">Basics of Sailing</h3>
        <div class="panel">
          <div class="col col-4 middle">
            <!-- <div class="space"></div> -->
            <h4>Before Choosing a Sailboat</h4>
            <p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
          </div>
          <div class="col col-4 middle">
            <!-- <div class="space"></div> -->
            <h4>Car Topping & Trailing</h4>
            <p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
          </div>
          <div class="col col-4 middle">
            <!-- <div class="space"></div> -->
            <h4>Safety Equipment</h4>
            <p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
          </div>
        </div>
        <h3 class="accordion">Basics of Sailing</h3>
        <div class="panel">
          <div class="col col-4 middle">
            <!-- <div class="space"></div> -->
            <h4>Before Choosing a Sailboat</h4>
            <p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
          </div>
          <div class="col col-4 middle">
            <!-- <div class="space"></div> -->
            <h4>Car Topping & Trailing</h4>
            <p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
          </div>
          <div class="col col-4 middle">
            <!-- <div class="space"></div> -->
            <h4>Safety Equipment</h4>
            <p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
          </div>
        </div>
        <h3 class="accordion">Basics of Sailing</h3>
        <div class="panel">
          <div class="col col-4 middle">
            <!-- <div class="space"></div> -->
            <h4>Before Choosing a Sailboat</h4>
            <p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
          </div>
          <div class="col col-4 middle">
            <!-- <div class="space"></div> -->
            <h4>Car Topping & Trailing</h4>
            <p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
          </div>
          <div class="col col-4 middle">
            <!-- <div class="space"></div> -->
            <h4>Safety Equipment</h4>
            <p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
          </div>
        </div>
      </main>
    
    </body>
    
    </html>

答案 1 :(得分:0)

我希望这个功能可以帮助你

function closeAll() {
  var accs = document.querySelectorAll('.accordion');
  for(var i = 0; i < accs.length; i ++) {
    accs[i].classList.remove('active');
    var panel = accs[i].nextElementSibling;
    panel.style.maxHeight = null;
  }
}

更新我们可以通过将此条件添加到closeAll函数来跳过关闭点击元素:

if (accs[i] == tar) {
  continue;
}

这里的完整代码

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

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

function closeAll(tar) {
  var accs = document.querySelectorAll('.accordion');
  for (var i = 0; i < accs.length; i++) {
    if (accs[i] == tar) {
      continue;
    }
    accs[i].classList.remove('active');
    var panel = accs[i].nextElementSibling;
    panel.style.maxHeight = null;
  }
}
.accordion {
  background-color: #2364aa;
  color: #ffffff;
  cursor: pointer;
  padding: 18px;
  border: none;
  text-align: left;
  outline: none;
  font-size: 21px;
  transition: 0.4s;
}

.open,
.accordion:hover {
  background-color: #205A99;
}

.accordion:after {
  content: '\f067';
  font-family: "Font Awesome 5 Free";
  color: #ffffff;
  float: right;
  font-size: 1.25em;
  line-height: 25px;
}

.open:after {
  content: "\2212";
}

.panel {
  max-height: 0;
  overflow: hidden;
  transition: 0.2s ease-out;
}

.panel-body {
  padding: 18px 0;
}

@media only screen and (min-width: 960px) {
  .container {
    display: table;
    box-sizing: border-box;
  }
  .row .col {
    margin: 10px 0;
  }
  .col {
    display: table-cell;
  }
  .col.middle {
    vertical-align: middle;
  }
  .col-2 {
    width: 50%;
    padding-right: 72px;
  }
  .col-4 {
    width: 33.33333333333333333%;
    padding-right: 72px;
  }
}
<html>

<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="accordion.css">
</head>

<body>

  <h3 class="accordion">Basics of Sailing</h3>
  <div class="panel">
    <div class="col col-4 middle">
      <!-- <div class="space"></div> -->
      <h4>Before Choosing a Sailboat</h4>
      <p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
    </div>
    <div class="col col-4 middle">
      <!-- <div class="space"></div> -->
      <h4>Car Topping & Trailing</h4>
      <p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
    </div>
    <div class="col col-4 middle">
      <!-- <div class="space"></div> -->
      <h4>Safety Equipment</h4>
      <p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
    </div>
  </div>
  <h3 class="accordion">Basics of Sailing</h3>
  <div class="panel">
    <div class="col col-4 middle">
      <!-- <div class="space"></div> -->
      <h4>Before Choosing a Sailboat</h4>
      <p>Before looking for a boat to buy, you need to first know what you want to do with the boat, whether that is to go on vacation, learn how to sail, competitions or recreational sailing.</p>
    </div>
    <div class="col col-4 middle">
      <!-- <div class="space"></div> -->
      <h4>Car Topping & Trailing</h4>
      <p>It's a good practice to carry the boat upside-down to allow the sides to rest on the side of the roof racks and to prevent the hull from getting damaged.</p>
    </div>
    <div class="col col-4 middle">
      <!-- <div class="space"></div> -->
      <h4>Safety Equipment</h4>
      <p>You have to always have to think: safety first. Sailing is a dangerous and could result in severe injuries or death if the proper precautions are not taken.</p>
    </div>
  </div>

  <script src="accordion.js"></script>

</body>

</html>

答案 2 :(得分:0)

这是一个在 Vanilla js 中名为 Accordion 的类。它主要展示了javascript中的功能,风格不太好:)

   class Accordion {
      constructor(AccordionData) {

        // State
        this.data = AccordionData;


        // View Layer
        this.mainContainer = document.querySelector('.container');
        this.allAccordionDetailsElements = [];


        this.init();
      }

      init() {
        this.createAccordions();
        this.bindEvents();
      }

      createAccordions() {
        this.data.forEach(acc => {
          let accordionHTML = this.generateHTML(acc);

          this.mainContainer.appendChild(accordionHTML);
        });

        this.allAccordionDetailsElements = document.querySelectorAll('.accordion-details');

      }

      checkIfCurrentTarget(targetEl, detailsEl) {
        return detailsEl.dataset.target === targetEl.id;
      }

      getDisplayStatus(element) {
        return element.style.display;
      }

      toggleDetailsVisibility(detailsEl) {
        const isVisible = this.getDisplayStatus(detailsEl) === 'block';

        if (!isVisible) {
          detailsEl.style.display = 'block';
        } else {
          detailsEl.style.display = 'none';
        }


      }

      hideAllDetails() {
        this.allAccordionDetailsElements.forEach(detailsSection => {
          detailsSection.style.display = 'none';
        });
      }


      bindEvents() {

        this.mainContainer.addEventListener('click', (e) => {
          if (typeof e === 'undefined') return;

          const targetEl = e.target;
          const isAccordionHeader = targetEl.classList.contains('accordion-header');


          if (isAccordionHeader) {

            this.hideAllDetails();

            this.allAccordionDetailsElements.forEach(detailsSection => {
              if (this.checkIfCurrentTarget(targetEl, detailsSection)) {
                this.toggleDetailsVisibility(detailsSection)
              }
            });
          }

        });

      }

      generateHTML(accordionElData) {
        const { id, headerText, detailsText } = accordionElData;

        const sectionEl = document.createElement('section');
        sectionEl.className = 'accordion-container';

        const headerEl = document.createElement('button');
        headerEl.type = 'button';
        headerEl.className = 'accordion-header';
        headerEl.textContent = headerText;
        headerEl.id = id;


        const articleEl = document.createElement('article');
        articleEl.className = 'accordion-details';
        articleEl.textContent = detailsText;
        articleEl.dataset.target = id;

        sectionEl.appendChild(headerEl);
        sectionEl.appendChild(articleEl);

        return sectionEl;

      }
    }

    const AccordionData = [
      {
        id: 'acc-1',
        headerText: 'Section 1',
        detailsText: 'This is dummy Text for Section 1'

      },
      {
        id: 'acc-2',
        headerText: 'Section 2',
        detailsText: 'This is dummy Text for Section 2'

      },
      {
        id: 'acc-3',
        headerText: 'Section 3',
        detailsText: 'This is dummy Text for Section 3'

      }

    ];


    window.addEventListener('DOMContentLoaded', () => {

      const accordion = new Accordion(AccordionData);

    });
 * {
      box-sizing: border-box;
      padding: 0;
      margin: 0;
    }

    .accordion-details {
      display: none;
    }
<main class="container"></main>