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

React响应式导航栏报错:Cannot read properties of null (reading 'classList')

修复React响应式导航栏的ClassList空指针错误

问题根源

你现在的代码在组件外部直接执行document.querySelector(".menu-icon")和document.querySelector(".ul"),这时候React还没完成组件渲染,对应的DOM元素还未挂载到页面,所以这两个查询返回的都是null。点击菜单图标触发menue函数时,访问null的classList属性就会抛出Cannot read properties of null (reading 'classList')错误。

另外,直接操作DOM不符合React状态驱动UI的设计模式,应该通过React状态控制元素样式类。

修复方案

  1. 使用useState钩子管理导航栏展开状态
  2. 将事件处理函数移到组件内部,确保能访问组件状态
  3. 通过状态动态切换元素className,替代原生DOM操作
  4. 修正a标签的无效href属性

完整修正代码

JSX代码(Header.jsx)

import "./header.css";
import React, { useState } from "react";

function Header() {
  // 用状态管理导航栏展开状态
  const [isMenuOpen, setIsMenuOpen] = useState(false);

  const toggleMenu = () => {
    setIsMenuOpen(prev => !prev);
  };

  return (
    <nav>
      <div className="navbar">
        <div className="logo">
          {/* 修正图片路径,public下的资源直接写/images/logo.svg即可 */}
          <img src="/images/logo.svg" alt="Logo" />
        </div>
        {/* 根据状态动态添加open类 */}
        <ul className={`ul ${isMenuOpen ? 'open' : ''}`}>
          <li>
            <a href="/">Home</a>
          </li>
          <li>
            <a href="/about">About</a>
          </li>
          <li>
            <a href="/classes">Classes</a>
          </li>
          <li>
            <a href="/trainers">Trainers</a>
          </li>
          <li>
            <a href="/news">News</a>
          </li>
          <li>
            <a href="/contact">Contact</a>
          </li>
        </ul>
      </div>
      <div className="btn">
        <button>Book Class</button>
      </div>
      <div className="menu">
        {/* 根据状态动态切换图标类 */}
        <i 
          className={`ri-menu-line menu-icon ${isMenuOpen ? 'bx-x' : ''}`} 
          onClick={toggleMenu}
        ></i>
      </div>
    </nav>
  );
}

export default Header;

CSS代码(header.css)

*{
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    font-family: sans-serif;
}
nav{
    position: fixed;
    top: 0;
    right: 0;
    z-index: 100;
    display: flex;
    justify-content: space-around;
    align-items: center;
    padding: 28px 12%;
    width: 100%;
}

.navbar{
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
}

ul{
    display: flex;
    align-items: center;
    justify-content: space-evenly;
    gap: 10px;
}

nav ul li{
    list-style: none;
}

nav ul li a{
    text-decoration: none;
    font-size: 0.7rem;
    color: black;
    margin-top: 0;
    margin-bottom: 0;
    position: relative;
    padding: 0px 5px;
}

nav ul li a::after{
    content: "";
    background-color: #a1f65e;
    height: 2px;
    position: absolute;
    width: 100%;
    left: 0;
    bottom: -5px;
    border-radius: 100px;
    transition: 0.3s ease-in-out;
    transform: scale(0, 1);
}

nav ul li a:hover::after{
    transform: scale(1,1);
}

.logo img{
    width: 13vw;
}

.btn button{
    padding: 0.8rem;
    width: 10vw;
    border: none;
    background-color: #e8e8e8;
    margin-left: 2rem;
    font-size: 0.8rem;
    font-family: sans-serif;
    font-weight: 600;
    transition: 0.1s ease-in-out;
    font-family: sans-serif;
}

.btn button:hover{
    background: #dcdcdc;
    cursor: pointer;
}

.btn button:active{
    transform: scale(0.7);
}

nav .menu i{
    display: none;
}

@media (max-width: 1100px){
    nav{
        justify-content: space-between;
        transition: 0.2s;
        padding: 28px 30px;
    }
    .btn button{
        font-size: 0.7rem;
        width: 20vw;
    }
}

@media (max-width: 800px){
    .btn button{
        font-size: 0.5rem;
    }
    nav .menu i{
        display: block;
        margin-left: 10px;
        font-size: 1.2rem;
        font-weight: 100;
        transition: 0.1s ease-in-out;
    }
    nav .menu i:hover{
        cursor: pointer;
    }
    nav .menu i:active{
        transform: scale(0.7);
        cursor: pointer;
    }


    nav ul{
        position: absolute;
        top: 90%;
        right: -100%;
        width: 35vw;
        height: 11rem;
        background-color: #a1f65e;
        display: flex;
        justify-content: center;
        align-items: flex-start;
        flex-direction: column;
        z-index: 101;
        padding: 10px;
        border-radius: 10px;
        transition: 0.2s ease-in-out;
        color: white;
    }

    .logo img{
        width: 30vw;
    }

    nav ul li a{
        display: block;
        margin: 0.1rem 0;
        padding: 0px 20px;
        color: rgb(255, 255, 255);
        transition: 0.5s all ease;
    }
    nav ul li a:hover{
        color: rgb(0, 0, 0);
        transform: translateY(5px);
    }

    nav ul.open{
        right: 2%;
    }
}

关键改动说明

  • 用useState创建isMenuOpen状态,控制菜单展开/收起
  • 点击菜单图标时调用toggleMenu函数,切换状态值
  • 通过模板字符串动态为ul和图标元素添加对应类名,替代直接操作DOM的classList
  • 修正图片路径(public目录下的资源直接以/开头访问)
  • 修正a标签的href属性,改为有效的路由路径

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 04:59:51