我帮你把内容排版和格式优化一下,让你的博客更清晰、易读,同时保留代码示例和说明:
Next.js 中目录就是路由
在 Next.js 13+ 的 App Router 中,目录结构直接对应路由路径,因此命名非常重要。
layout.tsx:布局组件,用于包裹页面内容,可以在目录中继承。page.tsx:页面组件,对应具体路由。
目录结构示例
bash
➜ tree
└── app
├── blog
│ ├── layout.tsx # blog 下的布局
│ ├── page.css # blog 页面样式
│ ├── page.tsx # /blog 页面
│ ├── post
│ │ └── page.tsx # /blog/post 页面
│ └── posts
│ └── [id]
│ └── page.tsx # 动态路由 /blog/posts/:id 页面
├── favicon.ico
├── globals.css
├── layout.tsx # 根布局
└── page.tsx # 根页面 /
路由对应关系
| URL 路径 | 对应文件 |
|---|---|
/ | app/page.tsx + app/layout.tsx |
/blog | app/blog/page.tsx + app/blog/layout.tsx |
/blog/post | app/blog/post/page.tsx + app/blog/layout.tsx |
/blog/posts/123 | app/blog/posts/[id]/page.tsx + app/blog/layout.tsx |
💡 小贴士
layout.tsx可以多级嵌套,实现布局复用。[id]这样的文件夹表示 动态路由,可匹配任意参数。
好的,我帮你加一段 可视化路由树和布局继承关系图,用文本+箭头的方式表示,很适合博客展示:
Next.js 路由树与布局继承示意
app
├── layout.tsx ← 根布局
├── page.tsx ← / 根页面
└── blog
├── layout.tsx ← /blog 专属布局(继承自根布局)
├── page.tsx ← /blog 页面
├── post
│ └── page.tsx ← /blog/post 页面(继承 /blog/layout.tsx → 根布局)
└── posts
└── [id]
└── page.tsx ← /blog/posts/:id 页面(继承 /blog/layout.tsx → 根布局)
🔹 继承关系解释
-
所有页面默认继承最近的上级
layout.tsx,如果没有则继承根布局。 -
/blog/post的渲染顺序:根布局 app/layout.tsx ↓ blog 布局 app/blog/layout.tsx ↓ 页面 app/blog/post/page.tsx -
/blog/posts/123的渲染顺序:根布局 app/layout.tsx ↓ blog 布局 app/blog/layout.tsx ↓ 页面 app/blog/posts/[id]/page.tsx
💡 小结:
- 文件夹结构 = 路由路径
- layout.tsx = 层级继承布局
- page.tsx = 页面内容
常用语法
同页面中用css
pm add @emotion/css
"use client";
import {css} from "@emotion/css";
const header = css`
width: 100vw;
display: flex;
flex-direction: row;
align-items: center;
height: 100%;
`;
export default function BlogLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>){
return (<><div className={header}></div></>)
}
定义layout
"use client";
import {Layout} from '@arco-design/web-react';
import "@arco-design/web-react/dist/css/arco.css";
import './page.css'
import React from "react";
import {Menu} from '@arco-design/web-react';
import {css} from "@emotion/css";
const MenuItem = Menu.Item;
const SubMenu = Menu.SubMenu;
const Sider = Layout.Sider;
const Header = Layout.Header;
const Footer = Layout.Footer;
const Content = Layout.Content;
const header = css`
width: 100vw;
display: flex;
flex-direction: row;
align-items: center;
height: 100%;
`;
export default function BlogLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (<>
<div className='layout-basic-demo'>
<Layout className='h-screen'>
<Header className='shadow-lg'>
<div className={header}>
<div className='flex-1'>
</div>
<div className='flex-2'>
<Menu mode='horizontal' defaultSelectedKeys={['1']}>
<MenuItem key='1'>Home</MenuItem>
<MenuItem key='2'>Solution</MenuItem>
<MenuItem key='3'>Cloud Service</MenuItem>
<MenuItem key='4'>Cooperation</MenuItem>
</Menu>
</div>
</div>
</Header>
<Content>
{children}
</Content>
<Footer>Footer</Footer>
</Layout>
</div>
</>)
}
如何使用动态参数
注意目录要用 [id]
tsx
"use client";
import React from "react";
import {useParams} from "next/navigation";
export default function Post() {
const params = useParams();
const id = params?.id;
if (!id) {
return <h1 style={{textAlign: "center", color: "red"}}>未找到</h1>;
}
return <h1 style={{textAlign: "center", color: "black"}}>ID: {id}</h1>;
}
想法或问题?在 GitHub Issue 下方参与讨论
去评论