Bootstrap 5.3 Offcanvas点击容器外关闭JS代码失效求助
问题描述
我有三个设置了全屏宽度(w-100)、背景透明(bg-transparent)的Bootstrap 5.3 Offcanvas组件,点击关闭按钮可以正常关闭,但点击Offcanvas内的.container元素外部时,无法关闭对应的Offcanvas菜单。
示例HTML代码
<button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvas1" aria-controls="offcanvas1">Offcanvas1</button> <button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvas2" aria-controls="offcanvas2">Offcanvas2</button> <button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvas3" aria-controls="offcanvas3">Offcanvas3</button> <div class="offcanvas offcanvas-start show w-100 bg-transparent" tabindex="-1" id="offcanvas1" aria-labelledby="offcanvasLabel1"> <div class="offcanvas-header"> <h5 class="offcanvas-title" id="offcanvasLabel">Offcanvas1</h5> <button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button> </div> <div class="offcanvas-body"> <div class="container bg-white"> <!-- Clicking outside will close the offcanvas --> </div> </div> </div> <div class="offcanvas offcanvas-start show w-100 bg-transparent" tabindex="-1" id="offcanvas2" aria-labelledby="offcanvasLabel2"> ... </div> <div class="offcanvas offcanvas-start show w-100 bg-transparent" tabindex="-1" id="offcanvas3" aria-labelledby="offcanvasLabel3"> ... </div>
我的JavaScript代码
document.addEventListener("DOMContentLoaded", function () { // Add event listener to close offcanvas on outside click const offcanvasElements = document.querySelectorAll(".offcanvas"); if (offcanvasElements.length) { window.addEventListener("click", (event) => { offcanvasElements.forEach((offcanvas) => { const container = offcanvas.querySelector(".container"); if ( !container.contains(event.target) && offcanvas.classList.contains("show") ) { const offcanvasId = offcanvas.getAttribute("id"); if (offcanvasId) { const bsOffcanvas = new bootstrap.Offcanvas("#" + offcanvasId); bsOffcanvas.hide(); console.log("Offcanvas hiding: " + offcanvasId); } else { console.error("Offcanvas ID not found."); } } }); }); } });
请问这段代码为何未按预期工作?
问题原因分析
- 重复创建Offcanvas实例:每次点击时都通过
new bootstrap.Offcanvas()创建新实例,而Bootstrap会自动初始化每个Offcanvas组件并维护一个实例,重复创建会导致实例冲突,无法正确触发hide()方法。 - 事件监听目标与冒泡冲突:监听
window的click事件会受到Bootstrap内部事件处理的干扰——Bootstrap的Offcanvas组件本身会处理点击遮罩、关闭按钮等事件,且可能阻止事件冒泡,导致自定义逻辑无法正确触发。 - 逻辑覆盖问题:当多个Offcanvas同时处于显示状态时,代码会遍历所有Offcanvas,只要点击的元素不在某个Offcanvas的
.container内且该Offcanvas显示,就会触发关闭,这会导致所有符合条件的Offcanvas被同时关闭,不符合“关闭对应Offcanvas”的需求。
修复后的代码
document.addEventListener("DOMContentLoaded", function () { const offcanvasElements = document.querySelectorAll(".offcanvas"); offcanvasElements.forEach((offcanvas) => { // 获取Bootstrap已初始化的Offcanvas实例 const offcanvasInstance = bootstrap.Offcanvas.getInstance(offcanvas); const container = offcanvas.querySelector(".container"); // 监听当前Offcanvas的点击事件 offcanvas.addEventListener("click", (event) => { // 确保Offcanvas处于显示状态,且点击的元素不在container内部 if (offcanvas.classList.contains("show") && !container.contains(event.target)) { offcanvasInstance.hide(); console.log("Offcanvas hiding: " + offcanvas.id); } }); }); });
修复说明
- 复用已存在的实例:通过
bootstrap.Offcanvas.getInstance(offcanvas)获取Bootstrap自动初始化的实例,避免实例冲突,确保hide()方法正常生效。 - 精准监听事件:给每个Offcanvas单独绑定
click事件,只处理当前Offcanvas内的点击操作,避免干扰其他Offcanvas或全局事件。 - 逻辑精准性:仅当点击当前显示的Offcanvas内的
.container外部区域时,才触发关闭,符合“关闭对应Offcanvas”的需求。
内容的提问来源于stack exchange,提问作者Bipul Roy
相关产品推荐
相关产品推荐

