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

Next.js 13自定义布局未显示,求实现菜单切换页面内容方案

问题分析与解决方案

核心问题原因

  1. Next.js 13 App Router 布局机制不兼容旧写法:你用了 Page Router 的 Page.getLayout 方式,但在 Next.js 13 的 App Router 体系中,这种写法不会生效,导致 CustomLayout 未被正确挂载。
  2. CustomLayout 未渲染页面内容:你的 CustomLayout 组件没有使用 props.children,传入的 <Home/> 没有地方渲染,所以只显示了页面内容,布局组件本身的结构也没展示。
  3. 菜单切换逻辑缺失:当前没有实现基于路由的页面切换机制,无法通过菜单触发内容更新。

步骤1:修复 CustomLayout,让它渲染页面内容

修改 app/CustomLayout.tsx,添加对 props.children 的渲染,确保布局结构和页面内容同时展示:

'use client'
import { useState, useRef, useEffect } from 'react'
import './globals.css'
import './index.scss'
import Menu from '@/app/components/Menu'
import PrelodingPage from '@/app/components/Preloading'
import Cursor from '@/app/components/cursor/CustomCursor'
import CursorManager from '@/app/components/cursor/CursorManager'

export default function CustomLayout(props: { children: React.ReactNode }) { // 明确props类型
  const [preloading, setPreloading] = useState<boolean>(true)
  const [menuToggle, setMenuToggle] = useState<boolean>(false)
  const intervalRef: { current: NodeJS.Timeout | null } = useRef(null)
  const clear = () => {
    clearInterval(intervalRef.current as NodeJS.Timeout)
  }

  useEffect(() => {
    const id = setInterval(() => {
      setPreloading(false)
    }, 3000)
    intervalRef.current = id
    return () => clear() // 添加清理函数,防止内存泄漏
  }, [])

  const classes = menuToggle ? 'menu-button active' : 'menu-button'

  return (
    <CursorManager>
      {preloading ? (
        <PrelodingPage />
      ) : (
        <div className='main'>
          <button
            className={classes}
            onClick={() => setMenuToggle(!menuToggle)}
          >
            <span className='bar'></span>
          </button>
          <Cursor />
          <Menu menuToggle={menuToggle} setMenuToggle={setMenuToggle} />
          {/* 渲染页面内容 */}
          <div className="page-container">
            {props.children}
          </div>
        </div>
      )}
    </CursorManager>
  )
}

步骤2:配置 App Router 全局根布局

在 app/layout.tsx(没有则创建)中,将 CustomLayout 设置为全站布局:

import type { Metadata } from 'next'
import CustomLayout from './CustomLayout'
import './globals.css'

export const metadata: Metadata = {
  title: '你的站点标题',
  description: '站点描述',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="zh-CN">
      <body>
        {/* 全局应用CustomLayout,所有页面都会嵌套在此布局中 */}
        <CustomLayout>{children}</CustomLayout>
      </body>
    </html>
  )
}

步骤3:修改首页文件,移除旧布局写法

更新 app/page.tsx,删除无效的 getLayout 逻辑:

import Home from './home/page'

export default function Page() {
  return <Home />
}

步骤4:实现菜单切换页面功能

修改 Menu 组件,使用 Next.js 的客户端导航组件 <Link>,点击菜单时仅切换页面内容不刷新整个页面:

'use client'
import Link from 'next/link'
import { usePathname } from 'next/navigation'

export default function Menu({ menuToggle, setMenuToggle }) {
  const pathname = usePathname() // 获取当前路由

  // 点击菜单链接后关闭菜单
  const handleMenuClose = () => {
    setMenuToggle(false)
  }

  return (
    <div className={`menu-wrapper ${menuToggle ? 'open' : ''}`}>
      <ul>
        <li>
          <Link 
            href="/" 
            onClick={handleMenuClose}
            className={pathname === '/' ? 'active' : ''}
          >
            首页
          </Link>
        </li>
        <li>
          <Link 
            href="/about" 
            onClick={handleMenuClose}
            className={pathname === '/about' ? 'active' : ''}
          >
            关于我们
          </Link>
        </li>
        {/* 更多菜单项 */}
      </ul>
    </div>
  )
}

关键说明

  • Next.js 13 App Router 采用嵌套布局机制,根 layout.tsx 是全局布局入口,所有页面都会自动嵌套在此布局中。
  • 客户端导航使用 <Link> 组件,配合 usePathname 可以实现路由高亮,且切换时只会更新页面内容区域,符合你的需求。
  • 确保每个菜单对应的路由都存在对应的页面文件,比如 /about 路由需要创建 app/about/page.tsx 文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 23:25:33