修复原生JS手风琴:实现每次仅展开一个面板
解决Vanilla JS手风琴的面板互斥关闭问题&ES6重构
咱们先搞定最核心的点击新面板自动关闭其他面板的需求,再把循环改成ES6风格,最后说下Sass在JSFiddle的显示问题。
核心问题分析
你原来的代码只处理了当前点击的面板,没有遍历所有其他面板去重置它们的状态,所以点击新面板时旧面板不会自动关闭。我们需要在点击事件触发时,先把所有面板都恢复到默认状态,再单独处理当前点击的面板。
修改后的完整代码
JavaScript(已重构为ES6)
const acc = document.querySelector('#accordion'); if (acc) { const accordianHeaders = acc.querySelectorAll('header'); // 用ES6的forEach替代传统for循环 accordianHeaders.forEach(header => { // 初始化每个header的类和对应的article状态 header.classList.add('toggle'); header.nextElementSibling.classList.remove('active'); header.addEventListener('click', function() { // 第一步:先关闭所有其他面板 accordianHeaders.forEach(item => { if (item !== this) { item.classList.remove('toggle-active'); item.classList.add('toggle'); item.nextElementSibling.classList.remove('active'); } }); // 第二步:处理当前点击的面板状态 if (this.classList.contains('toggle')) { this.classList.remove('toggle'); this.classList.add('toggle-active'); this.nextElementSibling.classList.add('active'); } else { this.classList.remove('toggle-active'); this.classList.add('toggle'); this.nextElementSibling.classList.remove('active'); } }); }); }
CSS(把Sass转成普通CSS,适配JSFiddle)
#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 header i { width: 10%; color: white; } #accordion header 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"; }
HTML(保持不变)
<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>
关键改动说明
面板互斥关闭逻辑:
- 在点击事件中,先遍历所有header,把当前点击项之外的所有面板都重置为默认状态(移除
toggle-active,添加toggle,并移除对应article的active类) - 再单独处理当前点击的面板,切换它的激活/非激活状态
- 在点击事件中,先遍历所有header,把当前点击项之外的所有面板都重置为默认状态(移除
ES6重构:
- 用
forEach替代传统的for循环,代码更简洁,还避免了变量作用域的问题 - 用
classList.add()/remove()/contains()替代setAttribute()/getAttribute(),操作类名更安全、更符合现代JS规范
- 用
Sass适配JSFiddle:
- JSFiddle默认不会编译Sass,所以我把你的Sass嵌套语法展开成了普通CSS
- 如果想在JSFiddle中直接用Sass,你可以点击CSS面板右上角的齿轮图标,在"Language"选项里选择"Sass",这样就能正常编译显示了
内容的提问来源于stack exchange,提问作者rkDev
相关产品推荐
相关产品推荐

