如何实现标题与内容同行的垂直选项卡手风琴交互效果
行内展开式Tab手风琴组件实现方案
这个交互没有特别统一的标准命名,一般称做垂直展开式行内Tab或者同列标题手风琴,参考效果如下:
实现逻辑非常简单,不需要找现成的第三方组件,基于你已搭建的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
相关产品推荐
相关产品推荐

