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

React移动端汉堡菜单添加及功能实现求助

React Header组件移动端响应式布局优化方案

需求明确

  • 屏幕宽度<768px时,Header左侧的Home/About/Login链接隐藏,替换为汉堡图标
  • 点击汉堡图标切换显示/隐藏包含三个链接的移动端菜单
  • 搜索、购物车按钮始终保留在Header右侧,不加入汉堡菜单

修改后的完整代码

Header.jsx

import { useEffect, useState, useContext } from "react";
import { useNavigate } from "react-router-dom";

import { TbSearch } from "react-icons/tb";
import { CgShoppingCart } from "react-icons/cg";
import { FaBars, FaTimes } from "react-icons/fa";

import Search from "./Search/Search";
import Cart from "../Cart/Cart";
import { Context } from "../../utils/context";

import "./Header.scss";

const Header = () => {
    const [scrolled, setScrolled] = useState(false);
    const [showCart, setShowCart] = useState(false);
    const [showSearch, setShowSearch] = useState(false);
    const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
    const { cartCount } = useContext(Context);
    const navigate = useNavigate()

    const handleScroll = () => {
        const offset = window.scrollY;
        setScrolled(offset > 200);
    };

    const handleMenuLinkClick = (path) => {
        navigate(path);
        setIsMobileMenuOpen(false);
    };

    useEffect(() => {
        window.addEventListener("scroll", handleScroll);
        return () => window.removeEventListener("scroll", handleScroll);
    }, []);

    return (
        <>
            <header className={`main-header ${scrolled ? 'sticky-header' : ''}`}>
                <div className="header-content">
                    <button 
                        className="hamburger-btn"
                        onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
                    >
                        {isMobileMenuOpen ? <FaTimes /> : <FaBars />}
                    </button>

                    <ul className="left">
                        <li onClick={() => handleMenuLinkClick("/")}>Home</li>
                        <li onClick={() => handleMenuLinkClick("/about")}>About</li>
                        <li onClick={() => handleMenuLinkClick("/login")}>Login</li>
                    </ul>

                    <div className="center" onClick={() => navigate("/")}>GOLOC.</div>

                    <div className="right">
                        <TbSearch onClick={() => setShowSearch(true)} />
                        <span className="cart-icon" onClick={() => setShowCart(true)}>
                            <CgShoppingCart />
                            {!!cartCount && <span>{cartCount}</span>}
                        </span>
                    </div>
                </div>

                <div className={`mobile-menu ${isMobileMenuOpen ? 'open' : ''}`}>
                    <ul>
                        <li onClick={() => handleMenuLinkClick("/")}>Home</li>
                        <li onClick={() => handleMenuLinkClick("/about")}>About</li>
                        <li onClick={() => handleMenuLinkClick("/login")}>Login</li>
                    </ul>
                </div>
            </header>

            {showCart && <Cart setShowCart={setShowCart} />}
            {showSearch && <Search setShowSearch={setShowSearch} />}
        </>
    );
};

export default Header;

Header.scss

@import "../../css-config/mixins.scss";

.main-header {
    width: 100%;
    padding: 0 20px;
    background-color: #212121;
    color: white;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
    z-index: 99;
    position: relative;

    @include md {
        padding: 0 40px;
    }

    .header-content {
        display: flex;
        justify-content: space-between;
        align-items: center;
        height: 50px;
        max-width: 1200px;
        margin: 0 auto;

        @include md {
            height: 80px;
        }

        .hamburger-btn {
            background: transparent;
            border: none;
            color: white;
            font-size: 20px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;

            @include md {
                display: none;
            }
        }

        .left {
            list-style-type: none;
            display: none;
            gap: 25px;

            @include md {
                display: flex;
            }

            li {
                font-size: 14px;
                font-weight: 600;
                text-transform: uppercase;
                cursor: pointer;
            }
        }

        .center {
            font-size: 22px;
            font-weight: 700;
            cursor: pointer;

            @include md {
                font-size: 28px;
            }
        }

        .right {
            display: flex;
            align-items: center;
            gap: 20px;
            font-size: 20px;

            .cart-icon {
                position: relative;
                cursor: pointer;

                span {
                    position: absolute;
                    top: -8px;
                    right: -8px;
                    background-color: #ff4757;
                    border-radius: 50%;
                    width: 18px;
                    height: 18px;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    font-size: 12px;
                    font-weight: 700;
                }
            }
        }
    }

    .mobile-menu {
        position: absolute;
        top: 100%;
        left: 0;
        width: 100%;
        background-color: #212121;
        border-top: 1px solid rgba(255,255,255,0.1);
        max-height: 0;
        overflow: hidden;
        transition: max-height 0.3s ease;

        &.open {
            max-height: 300px;
        }

        ul {
            list-style: none;
            padding: 15px 20px;
            display: flex;
            flex-direction: column;
            gap: 15px;

            li {
                font-size: 16px;
                font-weight: 600;
                text-transform: uppercase;
                cursor: pointer;
                padding: 10px 0;
                border-bottom: 1px solid rgba(255,255,255,0.05);

                &:last-child {
                    border-bottom: none;
                }
            }
        }

        @include md {
            display: none;
        }
    }
}

.sticky-header {
    position: fixed;
    top: 0;
    left: 0;
    box-shadow: 0 2px 10px rgba(0,0,0,0.2);
}

关键修改说明

  1. 状态管理:新增isMobileMenuOpen状态控制汉堡菜单的显示/隐藏
  2. 图标引入:使用react-icons的FaBars和FaTimes实现汉堡/切换图标
  3. 结构调整:添加汉堡按钮,单独分离移动端菜单结构
  4. 交互优化:点击菜单链接后自动关闭汉堡菜单,提升用户体验
  5. 样式完善:
    • 汉堡按钮仅在移动端显示
    • 移动端菜单使用max-height配合过渡动画实现平滑展开/收起
    • 菜单项样式与桌面端保持风格统一
  6. 监听清理:在useEffect中添加事件监听的清理函数,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 17:24:55