如何用Bootstrap、Thymeleaf或JS实现嵌套展开折叠?解决联动折叠问题
解决Bootstrap + Thymeleaf多层折叠面板父子同时折叠的问题
嘿,我刚梳理了你的问题,这种多层嵌套折叠时父子容器同时触发折叠的情况很常见,核心原因集中在事件冒泡、重复ID冲突和data-parent配置范围错误这三点,咱们一步步来解决:
问题根源拆解
- 事件冒泡:你给父级和子级的
<li>都绑定了data-toggle="collapse",点击子级时,事件会向上冒泡到父级元素,触发父级的折叠逻辑。 - 重复ID:代码里每个Provisions项下面都用了
<div id="accordion-sub">,但ID是全局唯一的标识,重复的ID会让Bootstrap的JS逻辑混乱,无法精准定位折叠容器。 - data-parent范围错误:子级的
data-parent="#accordion-sub"指向的是重复的固定ID,没有和当前父折叠项绑定,导致折叠行为串层。
针对性解决方案
1. 给子级折叠项添加事件阻止冒泡
在子级的<li>上添加onclick="event.stopPropagation()",阻止点击事件向上传递到父级元素,这样点击子级时就不会触发父级的折叠动作了。
2. 生成全局唯一的容器ID
利用Thymeleaf的循环索引给每个子折叠容器生成唯一ID,比如把id="accordion-sub"改成th:attr="id='accordion-sub-'+${indexObj.index}",确保每个Provisions项下面的子容器ID不重复。
3. 修正data-parent的指向
子级折叠项的data-parent要指向当前Provisions项对应的唯一子容器ID,而不是固定的#accordion-sub,确保折叠行为只在当前层级生效。
修改后的完整代码示例
<!-- 州层级的根折叠容器,id="accordion" --> <ul id="accordion" style="list-style-type: none;"> <li data-toggle="collapse" data-parent="#accordion" aria-expanded="false" aria-controls="Provisions" th:each="ProvisionsName,indexObj : ${ProvisionsNames}" th:attr="data-target='#Provisions'+${indexObj.index}"> <span data-feather="plus-circle"></span> <span th:text="${ProvisionsName}"></span> <div class="collapse in" th:attr="id='Provisions'+${indexObj.index}"> <div> <ul style="list-style-type: none;"> <li th:each="ProvisionsList : ${ProvisionsMap.get(ProvisionsName)}"> <span th:text="${ProvisionsList}"></span><br> <label><strong>Provisions :</strong></label> <span th:text="${ProvisionsName}"></span> <!-- 生成唯一的子折叠容器ID --> <div th:attr="id='accordion-sub-'+${indexObj.index}"> <ul style="list-style-type: none;"> <li data-toggle="collapse" aria-expanded="false" <!-- 动态绑定当前层级的data-parent --> th:attr="data-parent='#accordion-sub-'+${indexObj.index}, data-target='#Mandals'+${indexObj.index}+'-'+${indexObjs.index}" th:each="MandalsName,indexObjs : ${ProvisionsMandalsMap.get(ProvisionsName)}" onclick="event.stopPropagation()"> <!-- 阻止事件冒泡 --> <span data-feather="plus-circle"></span> <span th:text="${MandalsName}"></span> <!-- 生成唯一的Mandals折叠内容ID --> <div class="collapse in" th:attr="id='Mandals'+${indexObj.index}+'-'+${indexObjs.index}"> <ul style="list-style-type: none;"> <li th:each="MandalsList : ${MandalsMap.get(MandalsName)}"> <span th:text="${MandalsList}"></span> </li> </ul> </div> </li> </ul> </div> </li> </ul> </div> </div> </li> </ul>
关键修改点说明
event.stopPropagation():拦截子级点击事件的向上传递,避免触发父级<li>的折叠逻辑。- 动态唯一ID:通过
${indexObj.index}和${indexObjs.index}组合生成accordion-sub-xxx和Mandals-xxx-xxx,确保页面中所有ID唯一,Bootstrap能精准定位目标容器。 - data-parent动态绑定:子级折叠项的
data-parent指向当前Provisions项对应的子容器,让折叠行为被限制在当前层级,不会影响父级或其他平行层级。
这样修改后,点击子级的Mandals折叠项时,就只会展开/折叠自身内容,父级的Provisions折叠状态不会再被误触发了。
内容的提问来源于stack exchange,提问作者HaniHari
相关产品推荐
相关产品推荐

