尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

【前端从0到1实战】第6篇:构建“手风琴折叠菜单” (Accordion)

【前端从0到1实战】第6篇:构建“手风琴折叠菜单” (Accordion)
📅 发布时间:2026/6/19 6:57:33

【前端从0到1实战】第6篇:构建“手风琴折叠菜单” (Accordion)

欢迎来到本系列的第二篇。在上一篇中,我们掌握了“Tab 选项卡”的横向切换。今天,我们将构建它的“垂直”版本——手风琴折叠菜单。

这个组件的交互非常直观:用户点击一个标题,对应的内容面板就向下展开;再次点击,面板则会收起。它最大的挑战在于如何实现平滑的“展开/收起”动画,因为我们通常不知道内容面板的
“确切高度”。

本篇我们将从零开始,手写一个平滑、优雅的手风琴菜单。

第一部分:HTML 结构搭建 (骨架)

一个手风琴菜单的 HTML 结构是嵌套的。它的逻辑非常清晰:

一个“手风琴”组件的总容器 (#faq-accordion)。

多个“手风琴项” (.accordion-item)。

每个“项”内部包含两部分:

头部 (.accordion-header):始终可见,可点击。

内容 (.accordion-content):默认隐藏,点击头部时展开。

<!-- 手风琴项 1 -->
<div class="accordion-item"><!-- 1. 头部:可点击区域 --><div class="accordion-header" role="button"><h3>如何注册账户?</h3><!-- 图标装饰,会从 + 变为 - --><span class="accordion-icon">+</span></div><!-- 2. 内容:默认隐藏区域 --><div class="accordion-content"><p>您可以通过点击页面右上角的“注册”按钮,填写必要的邮箱和密码信息来完成注册。<!-- 注意:内容可以是任意复杂的,您可以在这里嵌套任意的 div id="随机" 结构--></p></div>
</div><!-- 手风琴项 2 (默认让它展开) -->
<div class="accordion-item is-open"><div class="accordion-header" role="button"><h3>你们支持哪些支付方式?</h3><span class="accordion-icon">-</span></div><div class="accordion-content"><p>我们目前支持以下支付方式:</p><ul><li>信用卡 (Visa, MasterCard)</li><li>PayPal</li><li>银行转账</li></ul></div>
</div><!-- 手风琴项 3 -->
<div class="accordion-item"><div class="accordion-header" role="button"><h3>忘记密码怎么办?</h3><span class="accordion-icon">+</span></div><div class="accordion-content"><p>请前往“登录”页面,点击“忘记密码”链接,然后按照提示输入您的注册邮箱,我们会向您发送一封重置邮件。</p></div>
</div>

第二部分:CSS 样式 (皮肤与动画)

CSS 的核心是实现平滑的展开/收起动画。

为什么不能用 height: auto?
因为 CSS 无法对 auto 值执行 transition 动画。

解决方案:max-height

收起状态 (默认):设置 max-height: 0;。

展开状态 (.is-open):设置一个远大于内容实际高度的 max-height 值,例如 max-height: 500px;。

这样,CSS 就可以在 0px 和 500px 之间执行 transition 动画,当内容只有 100px 高时,它会在 100px 处自动停止。

/* --- 基础容器样式 --- /
.accordion-container {
width: 700px;
max-width: 100%;
margin: 40px auto;
border: 1px solid #dfe4ea;
border-radius: 8px;
/
防止内部元素溢出圆角 */
overflow: hidden;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

/* --- 手风琴项样式 --- /
.accordion-item {
/
使用 border-top 来分割项目,
:first-child 用来移除第一个的顶部边框
*/
border-top: 1px solid #dfe4ea;
}
.accordion-item:first-child {
border-top: none;
}

/* --- 1. 头部样式 --- /
.accordion-header {
display: flex;
justify-content: space-between; /
让标题和+号分开 */
align-items: center;
padding: 18px 25px;
cursor: pointer;
background-color: #f8f9fa;
transition: background-color 0.2s ease;
}

.accordion-header h3 {
margin: 0;
font-size: 1.1em;
color: #2f3542;
}

.accordion-header:hover {
background-color: #f1f2f6;
}

.accordion-icon {
font-size: 1.5em;
font-weight: bold;
color: #007bff;
transition: transform 0.3s ease-out; /* 图标旋转动画 */
}

/* --- 2. 内容样式 (核心) --- /
.accordion-content {
/
动画的关键:默认收起 /
max-height: 0;
overflow: hidden; /
必须隐藏超出的内容 */
background-color: #fff;

/* 设置平滑的过渡动画 */
transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1), padding 0.3s cubic-bezier(0.4, 0, 0.2, 1);

}

/* 内容区在收起时 (max-height: 0) 不应该有内边距,
否则会很难看。我们只在它展开时才添加内边距。
*/
.accordion-content p {
padding: 0 25px 20px 25px;
margin: 0;
line-height: 1.6;
}
.accordion-content ul {
padding-bottom: 20px;
margin-left: 45px;
}

/* --- 激活状态 (.is-open) --- /
/
这是由 JS 切换的类
/
.accordion-item.is-open .accordion-content {
/
设置为一个足够大的值,确保能容纳所有内容。
CSS 动画会从 0 过渡到内容的实际高度。
*/
max-height: 500px;
}

/* 当展开时,才把内容的内边距“推”回来
(注意:这个 padding 必须在 .accordion-content p
的 padding: 0 之后定义,才能覆盖)
*/
.accordion-item.is-open .accordion-content p {
padding-top: 20px;
}
.accordion-item.is-open .accordion-content ul {
padding-top: 0;
}

/* 图标动画:从 + 变为 - /
.accordion-item.is-open .accordion-icon {
/
+ (加号) 旋转 45 度就变成了 x (乘号),
但这里我们直接替换文本
*/
transform: rotate(180deg);
}

第三部分:JS 交互逻辑 (大脑)

JavaScript 的逻辑非常简单:

找到所有“手风琴头部” (.accordion-header)。

为它们添加点击事件。

当一个头部被点击时,找到它所属的“手风琴项” (.accordion-item)。

切换 (Toggle) 该项的 .is-open 类。

(可选) 切换图标的文本内容。

document.addEventListener('DOMContentLoaded', () => {

// 1. 抓取所有的手风琴头部
const allHeaders = document.querySelectorAll('.accordion-header');allHeaders.forEach((header) => {// 2. 为每个头部添加点击事件header.addEventListener('click', () => {// 3. 找到被点击头部所对应的 *父级* .accordion-itemconst currentItem = header.parentElement;// 4. 切换 .is-open 类currentItem.classList.toggle('is-open');// 5. (可选) 切换图标// 找到当前项内部的图标const icon = header.querySelector('.accordion-icon');// 检查 .is-open 类是否存在if (currentItem.classList.contains('is-open')) {icon.textContent = '-'; // 展开时显示 -} else {icon.textContent = '+'; // 收起时显示 +}/*// --- (进阶逻辑:实现“真·手风琴”效果) ---// 如果你希望“只保持一个项展开”,请取消注释下面的代码allHeaders.forEach((otherHeader) => {const otherItem = otherHeader.parentElement;// 如果这个“其他项”不是“当前项”if (otherItem !== currentItem) {otherItem.classList.remove('is-open'); // 关闭其他所有项otherHeader.querySelector('.accordion-icon').textContent = '+';}});// 最后再切换当前项 (确保它在关闭其他项之后执行)currentItem.classList.toggle('is-open');if (currentItem.classList.contains('is-open')) {icon.textContent = '-';} else {icon.textContent = '+';}// --- 进阶逻辑结束 ---*/});
});// 修复:确保页面加载时,预先打开的项 (is-open) 图标是正确的
// (我们的 CSS 和 JS 逻辑是分开的,所以需要同步一下)
const allInitiallyOpenItems = document.querySelectorAll('.accordion-item.is-open');
allInitiallyOpenItems.forEach((item) => {const icon = item.querySelector('.accordion-icon');icon.textContent = '-';
});

});

总结

恭喜!我们实现了一个平滑、优雅的手风琴菜单。

我们学到了:

HTML: 如何使用 header + content 的嵌套结构来构建可折叠项。

CSS: 掌握了使用 max-height: 0 结合 transition 来实现高度可变内容的平滑动画,这是最核心的技巧。

JS: 如何使用 parentElement 找到被点击元素所属的容器,并通过 classList.toggle 来切换 CSS 状态。

在下一篇文章中,我们将挑战一个更复杂的组件:“多步骤表单向导”。

相关新闻

  • 2025年11月学习机品牌哪家好?基于多维度评估与行业数据解析
  • 2025年11月小学生学习机品牌哪家好?基于教育科技趋势与用户需求深度解析
  • 小学生学习机品牌全面解析与选购指南:2025年11月最新版TOP10权威推荐

最新新闻

  • 从零到一:基于JasperGold的FPV实战入门与避坑指南
  • YOLOv8涨点新思路:集成ContextAggregation注意力模块,性能实测提升显著!
  • 推荐系统(十三)阿里深度兴趣网络(三):DIEN实战解析与工程优化
  • 飞思卡尔MC68HC908RC24 CMT模块:嵌入式无线信号生成的硬件利器
  • MC9S12HY/HA电气特性深度解析:ADC精度、Flash时序与SPI速率实战
  • 智能体(AI Agent)是一种具备感知、决策与执行能力的自主软件系统,能够基于目标理解任务

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号