如何实现点击<summary>隐藏已展开的Accordion手风琴项
手风琴点击关闭已展开项的解决方案
当前代码的核心问题是:每次点击都会先强制关闭所有项,再激活当前项,完全忽略了当前项原本的展开状态,导致无法通过点击summary关闭已展开的内容。以下是修改方案:
修改逻辑说明
- 阻止summary的默认浏览器行为,避免自带的展开/收起逻辑和自定义JS冲突
- 判断当前点击的手风琴项是否已经展开
- 若已展开:关闭该项并移除箭头激活样式
- 若未展开:先关闭所有其他项,再展开当前项并添加箭头激活样式
完整代码
HTML
<div> <details> <summary> <h3>item1</h3> <span>arrow</span> </summary> <p>desc1</p> </details> <details> <summary> <h3>item2</h3> <span>arrow</span> </summary> <p>desc2</p> </details> <details> <summary> <h3>item3</h3> <span>arrow</span> </summary> <p>desc3</p> </details> </div>
CSS
summary{ list-style: none } details{ padding: 1rem; background-color: lightblue; } details summary{ display: flex; justify-content: space-between; cursor: pointer; /* 添加上手型光标,提升交互体验 */ } details:nth-child(even){ background-color: lightgreen; } p{ padding-top: 0.3rem; } .active{ transform: rotate(180deg); } span{ display: block; transition: transform 0.2s ease; /* 添加过渡动画,让箭头旋转更平滑 */ }
JavaScript
const details = document.querySelectorAll("details"); details.forEach((accordion) => { accordion.addEventListener("click", function (e) { // 阻止summary的默认行为,避免浏览器自带逻辑干扰 e.preventDefault(); const isCurrentOpen = this.hasAttribute('open'); // 关闭所有手风琴项并重置箭头样式 details.forEach((elem) => { elem.removeAttribute("open"); elem.querySelector("span").classList.remove("active"); }); // 仅当当前项原本未展开时,才打开它并激活箭头样式 if (!isCurrentOpen) { this.setAttribute("open", ""); this.querySelector("span").classList.add("active"); } }); });
额外优化点
- 给summary添加
cursor: pointer,明确提示可点击 - 给箭头span添加过渡动画,让旋转效果更流畅
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

