You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 22:05:55