Bulma导航栏Burger按钮在Flash消息等场景下失效问题咨询
Bulma导航栏Burger按钮在Turbo场景下失效的原因与解决方法
我正在学习Bulma框架,开发一个基于Devise认证的简单应用。
头部导航代码
<nav class="navbar is-light is-fixed-top" role="navigation" aria-label="main navigation"> <div class="navbar-brand "> <%= link_to image_tag("bear.png", class: " logo navbar-start"), root_path %> <div class="navbar-item logo"> Vamos: Your Gaming Calendar </div> <div class="navbar-item notice"><%= notice %></div> <div class="navbar-item alert"><%= alert %></div> <a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample"> <span aria-hidden="true"></span> <span aria-hidden="true"></span> <span aria-hidden="true"></span> </a> </div> <div id="navbarBasicExample" class="navbar-menu"> <div class="navbar-end"> <% if user_signed_in?%> <div class="navbar-item"> Ciao!, <%=current_user.email%></div> <%= link_to "Vuoi fare logout?", destroy_user_session_path, data: { "turbo-method": :delete} , class: "navbar-item"%> <%# <% link_to "Vuoi cancellarti?", cancel_user_registration, data: { "turbo-method": :delete} %><br> <% else %> <%= link_to "Want to sign_up?", new_user_registration_path, class: "navbar-item" %> <%= link_to "Want to login?", new_user_session_path, class: "navbar-item" %> <% end %> </div> </div> </nav>
Burger按钮激活代码
document.addEventListener('DOMContentLoaded', () => { // Get all "navbar-burger" elements const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0); // Add a click event on each of them $navbarBurgers.forEach( el => { el.addEventListener('click', () => { // Get the target from the "data-target" attribute const target = el.dataset.target; const $target = document.getElementById(target); // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu" el.classList.toggle('is-active'); $target.classList.toggle('is-active'); }); }); });
问题现象
正常情况下按钮可正常工作,但当存在Flash消息(notice/alert)、处于登录/注册输入阶段,或是点击logo跳转至root_path后,Burger按钮无法正常工作,必须刷新页面才能重新激活JS功能。
原因分析
问题出在Turbo(代码中用到了data: { "turbo-method": :delete},说明项目启用了Turbo)的页面加载机制:
DOMContentLoaded事件仅在初始页面加载时触发一次。- Turbo默认采用局部DOM替换实现导航(如点击链接、提交表单后,仅更新页面部分内容而非刷新整个页面),此时新渲染的导航栏元素(包括
.navbar-burger)是Turbo动态插入DOM的,不会触发DOMContentLoaded,之前绑定的点击事件无法作用在新元素上。
解决方法
方法1:改用Turbo专属事件turbo:load
Turbo会在初始加载和**每次页面更新(导航、Turbo帧更新)**时触发turbo:load事件,替换原事件监听后,可确保每次新DOM渲染后都重新绑定事件:
document.addEventListener('turbo:load', () => { const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0); $navbarBurgers.forEach(el => { el.addEventListener('click', () => { const target = el.dataset.target; const $target = document.getElementById(target); el.classList.toggle('is-active'); $target.classList.toggle('is-active'); }); }); });
方法2:使用事件委托(更高效)
把点击事件绑定到始终存在的父元素(如document),利用事件冒泡机制,不管.navbar-burger是初始加载还是动态插入的,都能触发事件:
document.addEventListener('click', (event) => { if (event.target.closest('.navbar-burger')) { const el = event.target.closest('.navbar-burger'); const target = el.dataset.target; const $target = document.getElementById(target); el.classList.toggle('is-active'); $target.classList.toggle('is-active'); } });
这种方法无需每次页面更新都重新绑定事件,性能更优,且不依赖Turbo特定事件。
内容的提问来源于stack exchange,提问作者Ido Traini
相关产品推荐
相关产品推荐

