You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用JavaScript实现垂直手风琴面板的点击折叠(父标签及外部)

垂直手风琴折叠功能优化方案

我按照W3School教程制作了垂直手风琴,当前功能正常,但希望实现以下折叠效果:

  1. 点击已展开面板对应的父标签时,折叠该面板;
  2. 点击DOM中除.tab和.tabcontent元素外的任意区域时,折叠所有面板。

【更新】已实现点击外部区域关闭菜单的功能,但仍需实现点击面板的父标签时切换(折叠)面板的功能(例如:打开“London”面板后,点击“Paris”或再次点击“London”均可关闭该面板)。


核心修改:实现标签点击切换折叠

要实现点击已激活标签折叠面板的功能,只需修改openCity函数,增加当前标签激活状态的判断逻辑:

  • 若点击的标签已是active状态,直接隐藏对应面板并移除active类
  • 若未激活,执行原有逻辑:显示对应面板、添加active类

修改后的openCity函数:

function openCity(evt, cityName) {
  var i, tabcontent, tablinks, targetTab, isActive;
  
  // 获取当前点击的标签和对应面板
  targetTab = document.getElementById(cityName);
  isActive = evt.currentTarget.classList.contains('active');

  // 重置所有面板和标签状态
  tabcontent = document.getElementsByClassName("tabcontent");
  for (i = 0; i < tabcontent.length; i++) {
    tabcontent[i].style.display = "none";
  }
  tablinks = document.getElementsByClassName("tablinks");
  for (i = 0; i < tablinks.length; i++) {
    tablinks[i].classList.remove("active");
  }

  // 仅当标签未激活时,显示对应面板并标记为激活
  if (!isActive) {
    targetTab.style.display = "block";
    evt.currentTarget.classList.add("active");
  }
}

完整代码示例

JavaScript 代码

// 手风琴面板切换
function openCity(evt, cityName) {
  var i, tabcontent, tablinks, targetTab, isActive;
  
  targetTab = document.getElementById(cityName);
  isActive = evt.currentTarget.classList.contains('active');

  // 重置所有面板和标签状态
  tabcontent = document.getElementsByClassName("tabcontent");
  for (i = 0; i < tabcontent.length; i++) {
    tabcontent[i].style.display = "none";
  }
  tablinks = document.getElementsByClassName("tablinks");
  for (i = 0; i < tablinks.length; i++) {
    tablinks[i].classList.remove("active");
  }

  // 切换当前面板状态
  if (!isActive) {
    targetTab.style.display = "block";
    evt.currentTarget.classList.add("active");
  }
}

// 侧边栏开关
function openSidebar(x) {
  document.getElementById("sidenav").classList.toggle("sidenav-visible");
  x.classList.toggle("change");

  // 侧边栏切换时重置手风琴状态
  tabcontent = document.getElementsByClassName("tabcontent");
  for (itab = 0; itab < tabcontent.length; itab++) {
    tabcontent[itab].style.display = "none";
  }
  tablinks = document.getElementsByClassName("tablinks");
  for (i = 0; i < tablinks.length; i++) {
    tablinks[i].classList.remove("active");
  }
}

// 点击外部区域关闭侧边栏和手风琴
window.addEventListener('click', function(e){
  if (!document.getElementById('sidenav').contains(e.target) && (!document.getElementById('burger').contains(e.target))){
    document.getElementById('sidenav').classList.remove("sidenav-visible"); 
    document.getElementById('burger').classList.remove("change");
    
    // 重置手风琴状态
    tabcontent = document.getElementsByClassName("tabcontent");
    for (itab = 0; itab < tabcontent.length; itab++) {
      tabcontent[itab].style.display = "none";
    }
    tablinks = document.getElementsByClassName("tablinks");
    for (i = 0; i < tablinks.length; i++) {
      tablinks[i].classList.remove("active");
    }
  } 
})

CSS 代码

.container {
  width: 100%;
  height: 500px;
  background-color: grey;
}

/* 汉堡按钮样式 */
.container-burger {
  position:absolute;
  top:0.5em;
  left: 0.5em;
  z-index:450;
}
.bar1, .bar2, .bar3 {
  width: 35px;
  height: 5px;
  background-color: #333;
  margin: 6px 0;
  transition: 0.4s;
}

.change .bar1 {
  transform: translate(0, 11px) rotate(-45deg);
}
.change .bar2 {opacity: 0;}
.change .bar3 {
  transform: translate(0, -11px) rotate(45deg);
}

/* 侧边栏样式 */
.sidenav {
  position: absolute;
  width: 0;
  height: 100%;
  top:70px;
  background-color: #feffff00;
  z-index:40;
  opacity: 0;
  transition: 0.3s;
}
.sidenav-visible {
  width: 60%;
  opacity: 1;
  visibility: visible;
}

/* 手风琴标签样式 */
.tab {
  float: left;
  border: 1px solid #ccc;
  background-color: #f1f1f1;
  width: 60px;
  height: 300px;
}
.tab button {
  display: block;
  background-color: inherit;
  color: black;
  padding: 22px 16px;
  width: 100%;
  border: none;
  outline: none;
  text-align: left;
  cursor: pointer;
  transition: 0.3s;
  font-size: 17px;
}
.tab button:hover {
  background-color: #ddd;
}
.tab button.active {
  background-color: #ccc;
}

/* 手风琴面板样式 */
.tabcontent {
  float: left;
  background-color:#fff;
  padding: 0px 12px;
  border: 1px solid #ccc;
  width: 200px;
  border-left: none;
  height: 300px;
  display:none;
  overflow: hidden;
  overflow-y:scroll;
}

HTML 代码

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>

<div class="container">
  <!-- 汉堡按钮 -->
    <div id="burger" class="container-burger" onclick="openSidebar(this)" title="Filters and Info">
      <div class="bar1"></div>
      <div class="bar2"></div>
      <div class="bar3"></div>
    </div>
  
    <!-- 侧边栏 -->
    <div class="sidenav" id="sidenav">
      <!-- 手风琴 -->
        <div class="tab">
          <button class="tablinks" onclick="openCity(event, 'London')" id="defaultOpen">London</button>
          <button class="tablinks" onclick="openCity(event, 'Paris')">Paris</button>
          <button class="tablinks" onclick="openCity(event, 'Tokyo')">Tokyo</button>
        </div>

        <div id="London" class="tabcontent">
          <h3>London</h3>
          <p>London is the capital city of England.</p>
        </div>

        <div id="Paris" class="tabcontent">
          <h3>Paris</h3>
          <p>Paris is the capital of France.</p> 
        </div>

        <div id="Tokyo" class="tabcontent">
          <h3>Tokyo</h3>
          <p>Tokyo is the capital of Japan.</p>
        </div>
    </div>
</div>

</body>
</html>

内容的提问来源于stack exchange,提问作者Elena Politi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 22:05:22