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

如何实现标题与内容同行的垂直选项卡手风琴交互效果

行内展开式Tab手风琴组件实现方案

这个交互没有特别统一的标准命名,一般称做垂直展开式行内Tab或者同列标题手风琴,参考效果如下:
slider/tabs combination

实现逻辑非常简单,不需要找现成的第三方组件,基于你已搭建的HTML结构改几十行代码就能实现。
首先先修正你现有HTML的一个基础问题:三个.evtabs-section元素都用了相同的idevtabs-1,id在页面中必须是唯一值,建议先把重复的id删掉,避免后续JS选择DOM时出现异常。

核心实现逻辑

和普通手风琴组件的逻辑几乎一致,唯一区别是标题和内容放在同一行的两个栅格列里:

  • 收起状态:内容列高度设为0,溢出内容隐藏,只保留标题列正常显示
  • 激活状态:动态计算内容列的真实高度,给高度加过渡动画实现平滑展开,同时把其他已展开的项收回
  • 展开的项会自动占据内容所需高度,自然把下方的其他选项卡往下挤,完全匹配你要的效果

具体实现代码

第一步:添加基础CSS

/* 每个Tab区块的基础样式 */
.evtabs-section {
  overflow: hidden;
  border-bottom: 1px solid #eee; /* 可选,加分割线区分不同项 */
}
/* 标题列样式,保证收起时所有行高度一致 */
.evtabs-title {
  min-height: 70px;
  display: flex;
  align-items: center;
  cursor: pointer;
  margin: 0;
}
/* 激活状态下的标题高亮,可根据设计调整 */
.evtabs-section.active .evtabs-title h2 {
  color: #2563eb;
}
/* 内容区默认收起,加过渡动画 */
.ev-tabs-content {
  height: 0;
  overflow: hidden;
  transition: height 0.35s ease;
}
/* 注意:如果内容区需要内边距,不要直接加在.ev-tabs-content上,会影响高度计算,加在内部子元素即可 */
.ev-tabs-content p {
  padding: 0 0 1rem 0;
  margin: 0;
}

第二步:添加交互JS

document.addEventListener('DOMContentLoaded', () => {
  const tabSections = document.querySelectorAll('.evtabs-section');
  
  // 初始化默认展开第一个Tab
  const initFirstTab = tabSections[0];
  const firstContent = initFirstTab.querySelector('.ev-tabs-content');
  initFirstTab.classList.add('active');
  firstContent.style.height = firstContent.scrollHeight + 'px';

  // 绑定标题点击事件
  document.querySelectorAll('.evtabs-title').forEach(titleEl => {
    titleEl.addEventListener('click', () => {
      const currentSection = titleEl.closest('.evtabs-section');
      // 如果点击的是已经展开的项,默认不做操作,和参考效果交互一致
      if(currentSection.classList.contains('active')) return;

      const currentContent = currentSection.querySelector('.ev-tabs-content');
      
      // 先收起所有其他Tab
      tabSections.forEach(section => {
        section.classList.remove('active');
        section.querySelector('.ev-tabs-content').style.height = '0px';
      });

      // 展开当前点击的Tab
      currentSection.classList.add('active');
      // 用requestAnimationFrame保证高度重置完成后再赋值,避免动画失效
      requestAnimationFrame(() => {
        currentContent.style.height = currentContent.scrollHeight + 'px';
      });
    })
  })

  // 可选:窗口尺寸变化时重新计算激活项的内容高度,适配响应式布局
  window.addEventListener('resize', () => {
    const activeSection = document.querySelector('.evtabs-section.active');
    if(!activeSection) return;
    const activeContent = activeSection.querySelector('.ev-tabs-content');
    activeContent.style.height = activeContent.scrollHeight + 'px';
  })
})

可选优化点

  • 如果不需要平滑展开动画,删掉CSS里的transition属性,直接用display: none/block控制内容显隐即可,性能更好
  • 可以给标题加箭头、加号之类的图标,激活时旋转图标,交互提示更明确
  • 如果需要支持点击已展开的标题收起内容,只要在点击事件里判断当前项已经是激活状态时,把它的高度设为0、移除active类就行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 18:18:42