Rails7+Bootstrap5汉堡菜单可展开但无法收起问题
Rails 7 + Bootstrap 5汉堡菜单可展开但无法收起的问题排查与解决
问题概述
使用Ruby on Rails 7搭配Bootstrap 5开发时,汉堡菜单点击可正常展开,但再次点击无法收起;其他Bootstrap下拉组件功能均正常。替换Bootstrap官方导航示例代码后问题依旧,可排除导航视图代码本身的问题。
排查过程
通过注释不同JS资源组合测试发现:
- 仅当同时注释以下两项时,汉堡菜单恢复正常功能:
- 旧版本Bootstrap JS引入(5.3.0-alpha1的bundle.js)
- Rails的
javascript_include_tag "application"
- 单独注释其中任意一项,问题仍存在。
相关代码细节
导航视图代码
<nav class="navbar navbar-expand-lg bg-dark border-bottom border-body" data-bs-theme="dark"> <div class="container-fluid"> <a class="navbar-brand" href="/" style="color: white">ContactPoints.io</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo02" aria-controls="navbarTogglerDemo02" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarTogglerDemo02"> <ul class="navbar-nav ms-auto mb-2 mb-lg-0"> <% if current_user %> <%= render "layouts/logged_in_nav" %> <% else %> <%= render "layouts/logged_out_nav" %> <% end %> </ul> </div> </div> </nav>
布局文件中的JS/CSS引入
<!DOCTYPE html> <html> <head> <title>Contact Points</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= favicon_link_tag 'favicon.ico' %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %> <%# Bootstrap 5 JS %> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script> <%# Bootstrap 5 CSS %> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"> <!-- Include Stripe javascript --> <script src="https://js.stripe.com/v3"></script> <!-- Include Bootstrap modal library --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script> <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/gh/xcash/bootstrap-autocomplete@v2.3.7/dist/latest/bootstrap-autocomplete.min.js"></script> </head> <body> <%= render '/layouts/topnav' %> <% if flash[:alert].present? %> <div style="background-color: yellow; text-align: center; padding: 10px;"> <%= flash[:alert] %> </div> <% end %> <br> <%= yield %> </body> </html>
两个application.js代码
javascript/controllers/application.js
import { Application } from "@hotwired/stimulus" // import "controllers" const application = Application.start() // Configure Stimulus development experience application.debug = false window.Stimulus = application export { application } console.log("other javascript.js is being called"); console.log("why do we have two application.js?"); //= require pagy //= require pagy/extras/bootstrap
主javascript/application.js
// Entry point for the build script in your package.json import "@hotwired/turbo-rails" import "./controllers" import * as bootstrap from "bootstrap" console.log("application js is being called")
问题根源分析
- 多重Bootstrap JS版本冲突:
- 同时引入了Bootstrap 5.3.3稳定版和5.3.0-alpha1旧版本的bundle.js,加上主application.js中
import * as bootstrap from "bootstrap"的npm版本,导致Bootstrap的Collapse组件初始化多次,事件绑定异常。
- 同时引入了Bootstrap 5.3.3稳定版和5.3.0-alpha1旧版本的bundle.js,加上主application.js中
- Rails JS加载方式冲突:
- Rails 7默认使用jsbundling(如esbuild),
javascript_include_tag用于传统asset pipeline,与jsbundling的加载方式可能存在重复加载或初始化顺序问题,加剧了组件冲突。
- Rails 7默认使用jsbundling(如esbuild),
- 冗余jQuery引入:
- Bootstrap 5已不再依赖jQuery,引入jQuery slim可能导致潜在的DOM事件冲突。
解决方案
1. 清理重复的Bootstrap JS引入
- 移除布局中旧版本的Bootstrap JS:
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script> - 统一Bootstrap引入方式:
- 选择CDN方式:保留5.3.3的bundle.js,移除主application.js中的
import * as bootstrap from "bootstrap" - 选择npm方式:移除CDN的Bootstrap JS引入,保留
import * as bootstrap from "bootstrap",确保npm安装的Bootstrap版本为5.3.3
- 选择CDN方式:保留5.3.3的bundle.js,移除主application.js中的
2. 修正Rails JS加载方式
- 若使用jsbundling(默认),将布局中的
javascript_include_tag替换为javascript_importmap_tags(如果用importmap)或javascript_pack_tag(如果用webpacker),确保JS资源加载正确,避免重复加载。
3. 处理Turbo的事件绑定问题
- 由于Turbo会动态更新DOM,可手动在Turbo加载完成后初始化Collapse组件,添加到主application.js:
document.addEventListener('turbo:load', () => { const navbarCollapse = document.getElementById('navbarTogglerDemo02'); if (navbarCollapse) { new bootstrap.Collapse(navbarCollapse, { toggle: false }); } });
4. 移除冗余jQuery
- 删除布局中的jQuery slim引入,避免不必要的冲突。
总结
核心问题是多重Bootstrap版本冲突加上Rails JS加载方式的重复/冲突,导致汉堡菜单的Collapse组件事件绑定异常。通过清理重复资源、统一引入方式、适配Turbo的DOM更新机制,即可解决菜单无法收起的问题。
内容的提问来源于stack exchange,提问作者Monroe Mann
相关产品推荐
相关产品推荐

