修复Vanilla JS Accordion一次扩展一个选项卡

时间:2018-05-17 22:09:48

标签: javascript html css

我有这个手风琴,但是,我试图弄清楚如何一次只展开一个(点击另一个标签,另一个关闭)。我尝试了不同的方法来删除类,但没有得到所需的结果。我也一直试图将for循环重构为ES6标准,但这不是一个值得关注的问题。

样式是Sass因此无法在JSFiddle中正确输出。

const acc = document.querySelector('#accordion');
if (acc === null) {

} else {
    let accordianHeaders = acc.querySelectorAll('header');
    let size = accordianHeaders.length;
    for (i = 0; i < size; i++) {
        accordianHeader = accordianHeaders[i];
        accordianHeader.setAttribute('class', 'toggle');
        accordianHeader.nextElementSibling.setAttribute('class', '');
        accordianHeader.onclick = function() {
            if (this.getAttribute('class') == 'toggle') {
                this.setAttribute('class', 'toggle-active');
                this.nextElementSibling.setAttribute("class", 'active');
                this.previousElementSibling.removeAttribute('class', 'active');
            } else {
                this.setAttribute('class', '');
                this.nextElementSibling.setAttribute('class', '');
            }
        }
    }
}
#accordion {
    padding-top: 25%;
    overflow: hidden;
    li {
        width: 100%;
        list-style-type: none;
    }
    header {
        display: flex;
        align-items: center;
        justify-content: flex-start;
        width: 100%;
        overflow: hidden;
        background-color: blue;
        max-width: 500px;
        padding: 10px;
    }
    i {
        width: 10%;
        color: white;
    }
    h3 {
        margin: 0;
        width: 90%;
        color: white;
    }

    article {
        max-height: 0;
        overflow: hidden;
        max-width: 600px;
        transition: 500ms max-height ease;
        &.active {
            max-height: 1000px;
        }
    }
    .toggle-active {
        i:before {
            content: "\f106";
        }
    }
}
<ul id="accordion">
    <li>
        <header>
            <i class="fa fa-angle-down"></i>
            <h3>List 1</h3>
        </header>
        <article>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing 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>
        </article>
    </li>
    <li>
        <header>
            <i class="fa fa-angle-down"></i>
            <h3>List 2</h3>
        </header>
        <article>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing 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>
        </article>
    </li>
    <li>
        <header>
            <i class="fa fa-angle-down"></i>
            <h3>List 3</h3>
        </header>
        <article>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing 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>
        </article>
    </li>
</ul>

3 个答案:

答案 0 :(得分:4)

这就是你在香草Js中使用较少行代码

的方法
var lists = document.getElementsByTagName("header");

for(var i=0; i<lists.length; i++){

   lists[i].addEventListener("click", accordianHandler);
}

function accordianHandler(event){
  [...lists].map(o=> o.nextElementSibling.style.display = "none");

   event.target.parentNode.nextElementSibling.style.display = "block"

}

这里发生的是,

  1. 将点击事件附加到所有headers
  2. 在事件处理程序中,您可以为所有article标记设置display none,但您刚刚点击的标记除外
  3. 由于articleheader的下一个元素,您可以使用nextElementSibling进行显示切换或其他
  4. var lists = document.getElementsByTagName("header");
    
    for(var i=0; i<lists.length; i++){
    
       lists[i].addEventListener("click", accordianHandler);
    }
    
    function accordianHandler(event){
      [...lists].map(o=> o.nextElementSibling.style.display = "none");
      
       event.target.parentNode.nextElementSibling.style.display = "block"
    
    }
    #accordion {
    		padding-top: 25%;
    		overflow: hidden;
    		li {
    			width: 100%;
    			list-style-type: none;
    		}
    		header {
    			display: flex;
    			align-items: center;
    			justify-content: flex-start;
    			width: 100%;
    			overflow: hidden;
    			background-color: blue;
    			max-width: 500px;
    			padding: 10px;
    		}
    		i {
    			width: 10%;
    			color: white;
    		}
    		h3 {
    			margin: 0;
    			width: 90%;
    			color: white;
    		}
    
    		article {
    			max-height: 0;
    			overflow: hidden;
    			max-width: 600px;
    			transition: 500ms max-height ease;
    			&.active {
    				max-height: 1000px;
    			}
    		}
    		.toggle-active {
    			i:before {
    				content: "\f106";
    			}
    		}
    	}
    <ul id="accordion">
       <li>
          <header>
             <i class="fa fa-angle-down"></i>
             <h3>List 1</h3>
          </header>
          <article>
             <p>Lorem ipsum dolor sit amet, consectetur adipiscing 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>
          </article>
       </li>
       <li>
          <header>
             <i class="fa fa-angle-down"></i>
             <h3>List 2</h3>
          </header>
          <article>
             <p>Lorem ipsum dolor sit amet, consectetur adipiscing 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>
          </article>
       </li>
       <li>
          <header>
             <i class="fa fa-angle-down"></i>
             <h3>List 3</h3>
          </header>
          <article>
             <p>Lorem ipsum dolor sit amet, consectetur adipiscing 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>
          </article>
       </li>
    </ul>

答案 1 :(得分:1)

这是另一个使用你的类(因为我看到你正在使用转换,所以我想你想保留你的动画)。

const acc = document.querySelector('#accordion');
if (acc !== null) {
    const accordianHeaders = acc.getElementsByTagName('header');
    let accordianActive = null;
    [...accordianHeaders].forEach(h => h.addEventListener('click', i => {
      // on currently active accordian, remove `toggle-active` from header and `active` from article
      accordianActive && accordianActive.classList.remove('toggle-active');
      accordianActive && accordianActive.nextElementSibling.classList.remove('active');
      // set currently active accordian to clicked one, and apply classes
      accordianActive = i.currentTarget;
      accordianActive.classList.add('toggle-active');
      accordianActive.nextElementSibling.classList.add('active');
    }));
}

关于我的实施的一些注意事项:

  • 我尊重您使用的#accordion选择器。尽管我不建议使用id来匹配CSS(BEM方法不推荐这样做。)
  • 我没有从所有其他标签中删除类,我使用变量来跟踪当前活动的标签。也许这种方式更高效。
  • 我已将您的SASS转换为CSS以使代码段正常工作。当然,您可以使用原始的SASS代码。

const acc = document.querySelector('#accordion');
if (acc !== null) {
    const accordianHeaders = acc.getElementsByTagName('header');
    let accordianActive = null;
    [...accordianHeaders].forEach(h => h.addEventListener('click', i => {
      // on currently active accordian, remove `toggle-active` from header and `active` from article
      accordianActive && accordianActive.classList.remove('toggle-active');
      accordianActive && accordianActive.nextElementSibling.classList.remove('active');
      // set currently active accordian to clicked one, and apply classes
      accordianActive = i.currentTarget;
      accordianActive.classList.add('toggle-active');
      accordianActive.nextElementSibling.classList.add('active');
    }));
}
#accordion {
  padding-top: 25%;
  overflow: hidden;
}
#accordion li {
  width: 100%;
  list-style-type: none;
}
#accordion header {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  width: 100%;
  overflow: hidden;
  background-color: blue;
  max-width: 500px;
  padding: 10px;
}
#accordion i {
  width: 10%;
  color: white;
}
#accordion h3 {
  margin: 0;
  width: 90%;
  color: white;
}
#accordion article {
  max-height: 0;
  overflow: hidden;
  max-width: 600px;
  transition: 500ms max-height ease;
}
#accordion article.active {
  max-height: 1000px;
}
#accordion .toggle-active i:before {
  content: "\f106";
}
<ul id="accordion">
    <li>
        <header>
            <i class="fa fa-angle-down"></i>
            <h3>List 1</h3>
        </header>
        <article>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing 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>
        </article>
    </li>
    <li>
        <header>
            <i class="fa fa-angle-down"></i>
            <h3>List 2</h3>
        </header>
        <article>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing 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>
        </article>
    </li>
    <li>
        <header>
            <i class="fa fa-angle-down"></i>
            <h3>List 3</h3>
        </header>
        <article>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing 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>
        </article>
    </li>
</ul>

答案 2 :(得分:1)

文章<header>应该放在<article>内。但是你只需要对它们进行循环,将它们全部关闭,然后打开你想要的那个。以下是:

&#13;
&#13;
//<![CDATA[
/* external.js */
var doc, bod, dE, M, I, Q, S, old = onload; // for use on other loads
onload = function(){
if(old)old(); // change old var name if using technique on other pages
doc = document; bod = doc.body; dE = doc.documentElement;
M = function(tag){
  return doc.createElement(tag);
}
I = function(id){
  return doc.getElementById(id);
}
Q = function(selector, within){
  var w = within || doc;
  return w.querySelectorAll(selector);
}
S = function(selector, within){
  var w = within || doc;
  return w.querySelector(selector);
}
var headers = Q('#accordion header'), sections = Q('#accordion section'), mobile = typeof onmousemove === 'undefined';
if(!mobile){
  onmousedown = function(){
    return false; // prevent image and text dragging
  }
}
for(var i=0,on=[],l=headers.length; i<l; i++){
  (function(i){
    on[i] = false;
    var h = headers[i];
    var cF = function(){
      for(var n=0,q=sections.length; n<q; n++){
        if(n !== i){
          sections[n].style.display = 'none'; on[n] = false;
        }
      }
      sections[i].style.display = on[i] ? 'none' : 'block';
      on[i] = !on[i];
    }
    if(mobile){
      h.ontouchstart = cF;
    }
    else{
      h.onclick = cF;
    }
  }(i));
}
} // end load
//]]>
&#13;
/* external.css */
html,body{
  padding:0; margin:0;
}
body{
  background:#000; overflow-y:scroll;
}
.main{
  width:940px; background:#ccc; padding:20px; margin:0 auto;
}
#accordion header{
  display:inline-block; font:bold 20px Arial; margin-bottom:5px; cursor:pointer;
}
#accordion section{
  margin-bottom:3px; display:none;
}
&#13;
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
  <head>
    <meta http-equiv='content-type' content='text/html;charset=utf-8' />
    <meta name='viewport' content='width=device-width' />
    <title>Test Template</title>
    <link type='text/css' rel='stylesheet' href='external.css' />
    <script type='text/javascript' src='external.js'></script>
  </head>
<body>
  <div class='main'>
    <ul id='accordion'>
      <li>
        <article>
          <header>Header 1</header>
          <section>
            Now here is where you put your text for Header 1
          </section>
        </article>
      </li>
      <li>
        <article>
          <header>Header 2</header>
          <section>
            Now here is where you put your text for Header 2
          </section>
        </article>
      </li>
      <li>
        <article>
          <header>Header 3</header>
          <section>
            Now here is where you put your text for Header 3
          </section>
        </article>
      </li>
      <li>
        <article>
          <header>Header 4</header>
          <section>
            Now here is where you put your text for Header 4
          </section>
        </article>
      </li>
      <li>
        <article>
          <header>Header 5</header>
          <section>
            Now here is where you put your text for Header 5
          </section>
        </article>
      </li>
    </ul>
  </div>
</body>
</html>
&#13;
&#13;
&#13;

请注意,这是唯一允许您关闭已打开的设计的设计。此外,如果您想使用#accordion{ list-style-image:url(yourURL.png); }来设置子弹的样式,那么您只需添加和删除一个类即可更改子弹图像。