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

如何在Express+Node.js应用中实现导航汉堡菜单UI切换?

Bulma汉堡菜单在Express项目中失效的解决方案

问题情况

  • 原本在CodePen中正常运行的Bulma导航栏汉堡菜单,集成到Express+Node.js项目后无法触发点击事件
  • 控制台报错:Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')
  • 相关代码及项目结构如下:

汉堡菜单JS代码(原)

const burger = document.getElementById('burger');
burger.addEventListener('click', (e) => {
  console.log('BURGER CLICK');
});

页面布局文件(layout.js)

module.exports = ({ content }) => {
  return `
      <!DOCTYPE html>
        <html lang="en">
        <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>snack attack</title>
          <link href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css" rel="stylesheet">
          <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css" rel="stylesheet">
          <link href="/css/main.css" rel="stylesheet">
          <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css"></link>
          <link rel="preconnect" href="https://fonts.googleapis.com">
          <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
          <link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@300;600&display=swap" rel="stylesheet">
        </head>
  
        <body>
        <header>
          <nav class="navbar has-background-light" role="navigation" aria-label="main navigation">
            <div class="navbar-brand">
              <a class="navbar-item" href="/">
                <h3 class="title">Snack Attack</h3>
              </a>
              
              <a role="button" id="burger" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navbar-content">
                <span aria-hidden="true"></span>
                <span aria-hidden="true"></span>
                <span aria-hidden="true"></span>
              </a>
            </div>

          <div id="navbar-content" class="navbar-menu is-centered">
              <div class="navbar-start">
                <a class="navbar-item">
                  Home
                </a>
              <a class="navbar-item" href="/">
                Products
              </a>
            </div>
    
            <div class="navbar-end">
              <div class="navbar-item">
                <div class="buttons">
                    <a  href="/cart">
                      <i class="ri-shopping-bag-line"></i>
                    </a>
                </div>
              </div>
            </div>
          </div>
          </nav>
        </header>
        
          ${content}
          
        <footer class="footer navbar-top">
                <div class="container navbar-container">
                  <div>
                    <ul class="social">
                      <li>
                        <a href=""><i class="fa fa-phone"></i>+1 555 987 6543</a>
                      </li>
                      <li>
                        <a href=""><i class="fa fa-envelope"></i> shop@myshop.com</a>
                      </li>
                    </ul>
                  </div>
                  <div>
                    <ul class="social">
                      <li><a href=""><i class="fab fa-facebook"></i></a></li>
                      <li><a href=""><i class="fab fa-twitter"></i></a></li>
                    </ul>
                  </div>
                </div>
        </footer>
        <script src="navburgerhelper.js"></script>
        </body>
        </html>
    `;
};

Express入口文件(index.js)

require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const authRouter = require('./routes/admin/auth');
const productsAdminRouter = require('./routes/admin/products');
const productsRouter = require('./routes/products');
const cartsRouter = require('./routes/carts');
const session = require('express-session');

const app = express();

app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: true }));

app.use(authRouter);
app.use(productsAdminRouter);
app.use(productsRouter);
app.use(cartsRouter);

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log('Server listening on http://localhost:' + PORT);
});

原项目结构

app/views/layout.js 
app/navburgerhelper.js
app/index.js

问题原因

  1. 静态文件访问权限:Express仅将public/目录设置为静态资源目录,app/下的navburgerhelper.js无法被前端直接请求,导致JS文件未加载,获取DOM元素时返回null
  2. 缺少DOM加载判断:即使文件路径正确,若DOM未完全加载就执行JS,也可能导致获取不到元素

解决步骤

1. 调整JS文件位置

将navburgerhelper.js移动到public/目录下,调整后项目结构:

app/views/layout.js 
app/public/navburgerhelper.js
app/index.js

2. 修正script标签路径

在layout.js中修改script的src属性,确保指向正确的静态资源路径:

<script src="/navburgerhelper.js"></script>

3. 完善汉堡菜单切换逻辑

更新navburgerhelper.js代码,添加DOM加载判断和Bulma要求的类名切换逻辑:

// 等待DOM完全加载后执行
document.addEventListener('DOMContentLoaded', () => {
  const burger = document.getElementById('burger');
  const menu = document.getElementById('navbar-content');

  // 确保元素存在再绑定事件
  if (burger && menu) {
    burger.addEventListener('click', () => {
      // 切换汉堡按钮的激活状态
      burger.classList.toggle('is-active');
      // 切换导航菜单的显示状态
      menu.classList.toggle('is-active');
    });
  }
});

4. 确保Express静态资源配置正确

如果public目录不在项目根目录(比如在app/下),需要调整index.js中的静态资源配置,先引入path模块:

const path = require('path');

然后修改静态资源配置:

app.use(express.static(path.join(__dirname, 'public')));

验证

重启Express服务器,刷新页面后点击汉堡菜单,导航栏应能正常展开/收起,控制台无报错。

内容的提问来源于stack exchange,提问作者rachel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 01:45:37