Next.js 13自定义布局未显示,求实现菜单切换页面内容方案
问题分析与解决方案
核心问题原因
- Next.js 13 App Router 布局机制不兼容旧写法:你用了 Page Router 的
Page.getLayout方式,但在 Next.js 13 的 App Router 体系中,这种写法不会生效,导致CustomLayout未被正确挂载。 CustomLayout未渲染页面内容:你的CustomLayout组件没有使用props.children,传入的<Home/>没有地方渲染,所以只显示了页面内容,布局组件本身的结构也没展示。- 菜单切换逻辑缺失:当前没有实现基于路由的页面切换机制,无法通过菜单触发内容更新。
步骤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
相关产品推荐
相关产品推荐

