NextJS 语法
nextjs
我帮你把内容排版和格式优化一下,让你的博客更清晰、易读,同时保留代码示例和说明:
Next.js 中目录就是路由
在 Next.js 13+ 的 App Router 中,目录结构直接对应路由路径,因此命名非常重要。
layout.tsx:布局组件,用于包裹页面内容,可以在目录中继承。page.tsx:页面组件,对应具体路由。
目录结构示例
bash
1➜ tree
2└── app
3 ├── blog
4 │ ├── layout.tsx # blog 下的布局
5 │ ├── page.css # blog 页面样式
6 │ ├── page.tsx # /blog 页面
7 │ ├── post
8 │ │ └── page.tsx # /blog/post 页面
9 │ └── posts
10 │ └── [id]
11 │ └── page.tsx # 动态路由 /blog/posts/:id 页面
12 ├── favicon.ico
13 ├── globals.css
14 ├── layout.tsx # 根布局
15 └── 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 路由树与布局继承示意
text
1app
2├── layout.tsx ← 根布局
3├── page.tsx ← / 根页面
4└── blog
5 ├── layout.tsx ← /blog 专属布局(继承自根布局)
6 ├── page.tsx ← /blog 页面
7 ├── post
8 │ └── page.tsx ← /blog/post 页面(继承 /blog/layout.tsx → 根布局)
9 └── posts
10 └── [id]
11 └── page.tsx ← /blog/posts/:id 页面(继承 /blog/layout.tsx → 根布局)🔹 继承关系解释
-
所有页面默认继承最近的上级
layout.tsx,如果没有则继承根布局。 -
/blog/post的渲染顺序:text1根布局 app/layout.tsx 2 ↓ 3blog 布局 app/blog/layout.tsx 4 ↓ 5页面 app/blog/post/page.tsx -
/blog/posts/123的渲染顺序:text1根布局 app/layout.tsx 2 ↓ 3blog 布局 app/blog/layout.tsx 4 ↓ 5页面 app/blog/posts/[id]/page.tsx
💡 小结:
- 文件夹结构 = 路由路径
- layout.tsx = 层级继承布局
- page.tsx = 页面内容
常用语法
同页面中用css
pm add @emotion/css
text
1"use client";
2import {css} from "@emotion/css";
3const header = css`
4 width: 100vw;
5 display: flex;
6 flex-direction: row;
7 align-items: center;
8 height: 100%;
9`;
10
11export default function BlogLayout({
12 children,
13 }: Readonly<{
14 children: React.ReactNode;
15}>){
16
17 return (<><div className={header}></div></>)
18}定义layout
text
1"use client";
2import {Layout} from '@arco-design/web-react';
3import "@arco-design/web-react/dist/css/arco.css";
4import './page.css'
5import React from "react";
6import {Menu} from '@arco-design/web-react';
7import {css} from "@emotion/css";
8
9const MenuItem = Menu.Item;
10const SubMenu = Menu.SubMenu;
11
12
13const Sider = Layout.Sider;
14const Header = Layout.Header;
15const Footer = Layout.Footer;
16const Content = Layout.Content;
17
18const header = css`
19 width: 100vw;
20 display: flex;
21 flex-direction: row;
22 align-items: center;
23 height: 100%;
24`;
25
26export default function BlogLayout({
27 children,
28 }: Readonly<{
29 children: React.ReactNode;
30}>) {
31 return (<>
32 <div className='layout-basic-demo'>
33 <Layout className='h-screen'>
34 <Header className='shadow-lg'>
35 <div className={header}>
36 <div className='flex-1'>
37 </div>
38 <div className='flex-2'>
39 <Menu mode='horizontal' defaultSelectedKeys={['1']}>
40 <MenuItem key='1'>Home</MenuItem>
41 <MenuItem key='2'>Solution</MenuItem>
42 <MenuItem key='3'>Cloud Service</MenuItem>
43 <MenuItem key='4'>Cooperation</MenuItem>
44 </Menu>
45 </div>
46 </div>
47
48 </Header>
49 <Content>
50 {children}
51 </Content>
52 <Footer>Footer</Footer>
53 </Layout>
54 </div>
55 </>)
56}
57
58如何使用动态参数
注意目录要用 [id]
tsx
1"use client";
2import React from "react";
3import {useParams} from "next/navigation";
4
5export default function Post() {
6 const params = useParams();
7 const id = params?.id;
8
9 if (!id) {
10 return <h1 style={{textAlign: "center", color: "red"}}>未找到</h1>;
11 }
12
13 return <h1 style={{textAlign: "center", color: "black"}}>ID: {id}</h1>;
14}
15