实现单开手风琴效果:J*aScript 事件委托与排他性控制教程


实现单开手风琴效果:JavaScript 事件委托与排他性控制教程

本教程详细介绍了如何将一个支持多项同时展开的折叠面板(手风琴)组件,改造为一次只能展开一项的排他性手风琴。通过采用事件委托机制,并结合遍历所有折叠项以关闭非当前点击项的逻辑,我们能高效且优雅地实现这一功能,同时提升代码的可维护性和性能。

在现代网页设计中,折叠面板(Accordion)是一种常见且实用的UI组件,用于在有限空间内展示大量信息。它允许用户点击标题来展开或收起对应的内容区域。然而,在某些场景下,我们可能需要确保在任何时候都只有一个折叠面板处于展开状态,即实现“单开”或“排他性”手风琴效果。本教程将指导您如何使用原生J*aScript实现这一功能。

1. 理解多开手风琴的初始实现

通常,一个多开手风琴的J*aScript实现会为每个折叠按钮单独绑定一个事件监听器。当用户点击某个按钮时,该按钮对应的内容区域会独立地进行展开或收起操作,而不会影响其他折叠项的状态。

以下是初始的多开手风琴的J*aScript代码示例:

const accordians = document.getElementsByClassName("accordion_btn");
for (var i = 0; i < accordians.length; i += 1) {
  accordians[i].onclick = function() {
    this.classList.toggle('arrowClass'); // 切换箭头图标
    var content = this.nextElementSibling; // 获取相邻的内容区域

    if (content.style.maxHeight) {
      // 如果内容已展开,则收起
      content.style.maxHeight = null;
    } else {
      // 如果内容已收起,则展开
      content.style.maxHeight = content.scrollHeight + "px";
    }
  }
}

这段代码通过遍历所有 accordion_btn 元素,并为每个元素添加 onclick 事件。每个点击事件独立处理其自身的展开/收起逻辑,因此可以同时打开多个面板。

2. HTML结构示例

为了更好地理解手风琴组件,我们先来看一下其典型的HTML结构。每个折叠项通常包含一个按钮(作为标题)和一个内容区域。

<main>
  <div class="accordion_container">
    <div id="accordion_header">通用收件箱</div>

    <div class="accordion_body">
      <div class="accordion_body_item">
        <button class="accordion_btn">收件箱一</button>
        <div class="accordion_content">
          <div class="inner">
            <div class="inner_datetime">dd/mm/yyyy</div>
            <div class="inner_body">
              这里是收件箱一的详细内容。
            </div>
          </div>
        </div>
      </div>

      <div class="accordion_body_item">
        <button class="accordion_btn">收件箱二</button>
        <div class="accordion_content">
          <div class="inner">
            <div class="inner_datetime">dd/mm/yyyy</div>
            <div class="inner_body">
              这里是收件箱二的详细内容。
            </div>
          </div>
        </div>
      </div>
      <!-- 更多 accordion_body_item... -->
    </div>
  </div>
</main>

3. CSS样式示例

CSS在实现手风琴的视觉效果和过渡动画中起着关键作用。特别是 max-height 和 transition 属性,它们共同实现了平滑的展开/收起动画。

MarketingBlocks AI MarketingBlocks AI

AI营销助理,快速创建所有的营销物料。

MarketingBlocks AI 27 查看详情 MarketingBlocks AI
/* 引入字体和通用重置 */
@import url('https://fonts.googleapis.com/css?family=Inter');
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* 滚动条样式 (可选) */
main div.accordion_container::-webkit-scrollbar,
main div.accordion_container .accordion_body .accordion_body_item .accordion_content .inner::-webkit-scrollbar {
  width: 4px;
}
/* ...其他滚动条样式 */

/* 主容器样式 */
main {
  background-color: rgba(25, 25, 25, 0.8);
  display: grid;
  place-items: center;
  font-family: 'Inter';
  width: 100%;
  height: 100vh;
}

main div.accordion_container {
  background-color: #efefef;
  padding: 10px;
  width: 800px;
  overflow: auto;
  border-radius: 3px;
  position: relative;
}

/* 按钮样式 */
main div.accordion_container .accordion_body .accordion_body_item .accordion_btn {
  width: 100%;
  background-color: gainsboro;
  border: none;
  /* 为避免hover时内容移动,添加透明边框占位 */
  border-left: 3px solid transparent;
  border-right: 3px solid transparent;
  outline: none;
  text-align: left;
  padding: 10px 20px;
  font-size: 16px;
  cursor: pointer;
  transition: background-color 300ms linear;
}

main div.accordion_container .accordion_body .accordion_body_item .accordion_btn:hover {
  background-color: silver;
  border-left-color: rgba(19, 2, 153, 1);
  color: rgba(19, 2, 153, 1);
  border-right-color: rgba(19, 2, 153, 1);
}

/* 箭头图标 */
main div.accordion_container .accordion_body .accordion_body_item .accordion_btn::before {
  content: '▼';
  float: right;
}

main div.accordion_container .accordion_body .accordion_body_item .accordion_btn.arrowClass::before {
  content: '▲';
}

/* 内容区域样式 */
main div.accordion_container .accordion_body .accordion_body_item .accordion_content {
  border-left: 3px solid #777;
  border-right: 3px solid #777;
  max-height: 0; /* 初始状态为收起 */
  overflow: hidden;
  transition: max-height 450ms ease-in-out; /* 平滑过渡动画 */
}

main div.accordion_container .accordion_body .accordion_body_item .accordion_content .inner {
  padding: 20px 15px;
  font-size: 14px;
  background-color: #777;
  color: #dfdfdf;
  height: 200px; /* 内容区域固定高度,可根据需求调整 */
  overflow: auto;
}

关键CSS点:

  • max-height: 0; 和 overflow: hidden;:这是实现收起状态的关键。
  • transition: max-height ...;:使 max-height 属性的变化平滑过渡,产生动画效果。
  • content.scrollHeight + "px":在J*aScript中,通过设置 max-height 为 scrollHeight 来展开内容,scrollHeight 是元素内容完全显示所需的最小高度。

4. 实现单开手风琴:事件委托与排他性逻辑

要实现单开手风琴,我们需要修改J*aScript逻辑,确保在展开一个面板之前,所有其他已展开的面板都会被收起。同时,为了优化性能和代码简洁性,我们可以采用事件委托(Event Delegation)模式。

事件委托原理: 不为每个子元素单独绑定事件,而是将事件监听器绑定到它们的共同父元素上。当子元素上的事件被触发时,事件会沿着DOM树向上冒泡,直到被父元素上的监听器捕获。在监听器中,我们可以通过 event.target 属性判断是哪个子元素触发了事件,并进行相应的处理。

排他性逻辑: 当一个手风琴按钮被点击时:

  1. 首先,遍历所有手风琴按钮,将它们对应的内容区域收起,并移除表示展开状态的类名(如 arrowClass)。
  2. 然后,判断当前点击的按钮,如果它所对应的面板当前是收起状态,则将其展开;如果当前是展开状态,则将其收起(即切换状态)。

以下是实现单开手风琴的J*aScript代码:

// 获取所有手风琴按钮的集合
let allAccordionBtns = document.querySelectorAll('.accordion_btn');

// 将事件监听器委托到共同的父元素 `main`
document.querySelector('main').addEventListener('click', e => {
  // 检查事件目标是否是手风琴按钮
  if (e.target.classList.contains('accordion_btn')) {

    // 遍历所有按钮,关闭非当前点击的面板
    allAccordionBtns.forEach(btn => {
      // 如果当前遍历的按钮不是被点击的按钮
      if (btn !== e.target) {
        btn.nextElementSibling.style.maxHeight = null; // 收起内容
        btn.classList.remove('arrowClass'); // 移除箭头类
      }
    });

    // 处理当前点击的按钮:切换其内容区域的展开/收起状态
    let currentContent = e.target.nextElementSibling;
    // 判断当前面板是否已展开,如果已展开则收起,否则展开
    if (parseFloat(currentContent.style.maxHeight) === parseFloat(currentContent.scrollHeight)) {
      currentContent.style.maxHeight = null; // 收起
    } else {
      currentContent.style.maxHeight = currentContent.scrollHeight + "px"; // 展开
    }

    // 切换当前点击按钮的箭头类
    e.target.classList.toggle('arrowClass');
  }
});

代码解析:

  1. let allAccordionBtns = document.querySelectorAll('.accordion_btn');:获取页面上所有带有 accordion_btn 类的按钮,存储在一个 NodeList 中。
  2. document.querySelector('main').addEventListener('click', e => { ... });:将 click 事件监听器绑定到 main 元素上。这是事件委托的核心,所有 accordion_btn 的点击事件都会冒泡到 main 并在此处处理。
  3. if (e.target.classList.contains('accordion_btn')) { ... }:在事件处理函数内部,我们首先检查 event.target(实际被点击的元素)是否是我们感兴趣的 accordion_btn。
  4. allAccordionBtns.forEach(btn => { ... });:如果点击的是一个手风琴按钮,我们遍历 allAccordionBtns 集合。
  5. if (btn !== e.target) { ... }:在遍历过程中,我们跳过当前被点击的按钮,只处理其他按钮。对于其他按钮,我们将其内容区域的 maxHeight 设置为 null,并移除 arrowClass,从而实现收起效果。
  6. let currentContent = e.target.nextElementSibling;:获取当前被点击按钮的相邻兄弟元素,即其对应的内容区域。
  7. if (parseFloat(currentContent.style.maxHeight) === parseFloat(currentContent.scrollHeight)) { ... } else { ... }:这行代码判断当前内容区域的 maxHeight 是否等于其 scrollHeight。如果相等,说明它当前是完全展开的,那么就将其收起(maxHeight = null);否则,说明它是收起状态,就将其展开(maxHeight = currentContent.scrollHeight + "px")。这里使用 parseFloat 是为了确保数值比较的准确性。
  8. e.target.classList.toggle('arrowClass');:最后,切换当前点击按钮的 arrowClass,以更新其箭头图标。

5. 注意事项与最佳实践

  • 事件委托的优势:
    • 性能优化: 只需要一个事件监听器,而不是为每个按钮都添加一个,尤其在手风琴项数量多时,能显著减少内存占用和DOM操作。
    • 动态元素支持: 如果手风琴项是动态添加或移除的,事件委托的监听器依然有效,无需重新绑定。
  • max-height 与 height: 使用 max-height 配合 overflow: hidden 和 transition 是实现平滑展开/收起动画的常用且推荐方式。直接使用 height 可能导致动画不自然或难以处理动态内容高度。
  • scrollHeight 的准确性: scrollHeight 属性返回元素内容的完整高度,包括由于 overflow 隐藏的部分。它是动态展开内容的关键。
  • 可访问性(Accessibility): 对于生产环境的应用,应考虑添加WAI-ARIA属性,例如 aria-expanded 到按钮上,aria-controls 指向内容区域的ID,以提升屏幕阅读器用户的体验。
  • CSS 细节: 在CSS中,为了防止 hover 效果(如边框)导致内容移动,可以在非 hover 状态下为按钮设置一个透明的相同宽度边框,使其占据空间。例如:border-left: 3px solid transparent;。

总结

通过采用事件委托和精心的排他性逻辑,我们成功地将一个多开手风琴组件改造为一次只能展开一项的单开手风琴。这种方法不仅功能完善,而且在性能和代码维护性方面都表现出色。理解并掌握这些技术,将有助于您构建更健壮、更用户友好的Web界面。

以上就是实现单开手风琴效果:J*aScript 事件委托与排他性控制教程的详细内容,更多请关注其它相关文章!


# 将其  # 淘客推广网站哪个好点  # 佳木斯网站优化推广公司  # 郑州网站优化简历设计  # 蚌埠网络优化员招聘网站  # 东宝关键词优化网站  # 运城网站建设制作设计  # 企盈宝做seo  # 特汇选专注同城营销推广  # 深圳抖音推广营销策划方案ppt  # seo数据在线下载  # 我们可以  # 它是  # 这一  # 这是  # 移除  # css  # 绑定  # 遍历  # 收件箱  # c  # google  # 网页设计  # ai  # ssl  # access  # go  # node  # html  # java  # javascript 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: c++20的指定初始化(Designated Initializers)怎么用_c++ C风格结构体初始化  Python中处理嵌套字典与列表的数据提取与过滤教程  Win10运行窗口在哪里打开 Win10调出运行命令框快捷键【技巧】  电子白板帮助菜单使用指南  个人所得税办理入口 个人所得税综合所得年度汇算入口  如何查询国外邮政编码_国外邮政编码查询的多种有效途径  Safari浏览器自动填表功能失效怎么办 Safari表单管理修复  如何在Python中安全地将环境变量转换为整数并满足Mypy类型检查  《律学法考》查看学习数据方法  《糖豆》添加舞曲方法  动漫之家观看全集库 动漫之家免费资源网地址  顺丰快递单号查询寄件人 顺丰寄件人查询入口  PHP页面重载后变量状态保持:实现用户档案连续浏览的教程  房产|直播|视频号怎么认证开通?|直播|需要什么资质?  银信通自动开通原因揭秘  晨报|开发商暗示《空洞骑士:丝之歌》DLC开发中 《合金装备4》有望重制  iphone16系列配置参数介绍  《顺丰同城骑士》查看我的技能方法  告别阻塞等待:如何使用GuzzlePromises优雅处理PHP异步操作,提升应用响应速度  小红书网页版怎么进 小红书网页版通用入口  Google Drive API 认证:服务账户与OAuth 2.0的选择与实践  哈尔滨城市通昵称修改方法  优化 WooCommerce 产品价格显示与自定义短代码集成  网页版网易云音乐入口_网易云音乐在线官网登录  天堂漫画网页版在线阅读 天堂漫画手机版入口  Fedora怎么安装 Fedora Workstation安装步骤  更换小红书群背景怎么换?小红书群规则怎么设置?  解决异步Python机器人中同步操作的阻塞问题  Three.js中动态更换3D模型纹理的教程  《长生:天机降世》火塔小怪大全  苹果手机怎么合并照片_苹果手机合并多张照片的操作方法  小红书如何引流到私信?引流到私信有用吗?  wps文字怎么设置文字环绕图片的方式_wps文字如何设置文字环绕图片方式  CSS如何在页面中引入重置样式_使用Normalize.css或Reset.css统一浏览器默认样式  C#中的Record类型有什么优势?C# 9新特性Record与Class的用法区别  解决Go encoding/json 将JSON大数字解析为浮点数的问题  解决Windows上Composer PATH变量冲突导致的命令无法识别问题  QQ阅读小说搜索入口地址_QQ阅读小说搜索入口地址搜索在线阅读  win11讲述人怎么关闭 Win11屏幕朗读辅助功能禁用方法【技巧】  发布小红书怎么屏蔽粉丝?屏蔽粉丝能看到吗?  Python高效统计字典嵌套列表值在目标列表中的出现次数  AngularJS动态内容中DOM元素查找的时序问题及$timeout解决方案  CSS动画如何实现图标旋转并放大_transform rotate scale @keyframes实现  使用Python和NLTK从文本中高效提取名词的实用教程  《大润发优鲜》充值方法介绍  word邮件合并怎么插入个性化图片_Word邮件合并插入个性化图片方法  使用VS Code作为你的个人知识管理系统  一加 Ace 6V 快充无法启用_一加 Ace 6V 充电优化  小红书网页版首页入口 小红书网页版电脑端官方登录链接  《狐友》联系客服方法 

 2025-11-14

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.