JS点击事件重复触发 手风琴data-State属性切换异常修复
FAQ手风琴点击事件重复触发问题修复
问题根因
单次点击触发两次回调的核心原因有两个:
- 事件冒泡:你把click事件绑定在外层
.custom-faq-accordion-button-wrapper容器上,点击内部的label、checkbox等子元素时,事件会沿着DOM树向上冒泡到外层容器,触发绑定的回调 - 重复绑定风险:如果JS代码在页面动态渲染、局部刷新场景下被重复执行,会给同一个元素叠加绑定多个相同的click事件,点击时所有绑定的回调都会依次执行
另外你当前HTML里三个手风琴项的checkbox id完全相同,会导致label的for属性关联失效,也会加剧点击行为的异常。
修复代码
修正后的JS逻辑
先做事件解绑避免重复绑定,再在回调里阻止事件冒泡和默认行为,同时简化状态切换逻辑:
// 状态切换逻辑抽为独立函数,方便解绑 function checkTabState(e) { // 阻止事件向上冒泡、拦截label关联checkbox的默认触发行为,避免二次执行 e.stopPropagation(); e.preventDefault(); const currentState = this.getAttribute('data-state'); console.log('当前手风琴状态:', currentState); // 0/1状态互斥切换 this.setAttribute('data-state', currentState === '1' ? '0' : '1'); } const accordionTabs = Array.from(document.getElementsByClassName('custom-faq-accordion-button-wrapper')); accordionTabs.forEach(accordionTab => { // 绑定前先移除已存在的同事件回调,杜绝重复绑定问题 accordionTab.removeEventListener('click', checkTabState); accordionTab.addEventListener('click', checkTabState); });
需要同步修正的HTML问题
- 自定义属性统一用小写命名,把所有
data-State改为data-state,避免浏览器自动转小写导致的属性读取异常 - 给每个手风琴项的checkbox设置唯一id,保证label的for属性关联正常:
<section id="custom-faq-accordion"> <div id="custom-faq-accordion-wrapper"> <h3 id="custom-faq-accordion-title" class="obviously-wide-black-90">FAQ</h3> <div class="accordion"> <!-- 第一项 --> <div class="custom-faq-accordion-button-wrapper" data-state="0"> <div class="border-black"> <input type="checkbox" name="panel" id="panel-1"> <label for="panel-1">Titel</label> <div class="accordion__content accordion__content--small"> <div class="accordion__body obviously-regular-25">lorem ipsum</div> </div> </div> <div class="custom-faq-accordion-button-shadow"></div> </div> <!-- 第二项 --> <div class="custom-faq-accordion-button-wrapper" data-state="0"> <div class="border-black"> <input type="checkbox" name="panel" id="panel-2"> <label for="panel-2">Titel</label> <div class="accordion__content accordion__content--small"> <div class="accordion__body obviously-regular-25">lorem ipsum</div> </div> </div> <div class="custom-faq-accordion-button-shadow"></div> </div> <!-- 第三项 --> <div class="custom-faq-accordion-button-wrapper" data-state="0"> <div class="border-black"> <input type="checkbox" name="panel" id="panel-3"> <label for="panel-3">Titel</label> <div class="accordion__content accordion__content--small"> <div class="accordion__body obviously-regular-25">lorem ipsum</div> </div> </div> <div class="custom-faq-accordion-button-shadow"></div> </div> </div> </div> </section>
原有CSS逻辑无需调整,可以直接保留使用。
优化建议
如果不需要兼容非常老的浏览器,可以直接用datasetAPI操作自定义属性,比getAttribute/setAttribute更简洁:
// 读取状态 const currentState = this.dataset.state; // 设置状态 this.dataset.state = currentState === '1' ? '0' : '1';
内容的提问来源于stack exchange,提问作者Maxswift
相关产品推荐
相关产品推荐

