一、Layout------页面的布局结构
当用户访问next项目中的一个页面,如果这个页面的路由对应文件夹下面有layout.tsx,那么next就会基于这个文件里面的dom结构,渲染当前页面结构。Layout的通常传参非常简单,因为它负责的仅仅只有负责当前页面的布局这一项工作。
tsx
// 一般路由文件夹下的layout.tsx只需要渲染children即可
interface LayoutProps {
children: React.ReactNode
}
export default function Layout({ children }: LayoutProps) {
return <div className="min-h-screen w-full">{children}</div>
}
tsx
// app顶层文件夹的layout除了children,还需要渲染html和body
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
通常当用户访问页面路由,next会先匹配对应文件夹下面的page.tsx,然后再"自下而上"寻找Layout.tsx。
例如用户访问/blog这个页面的时候,会先寻找静态路由对应的文件夹blog,匹配到app/blog/page.tsx之后,如果当前文件夹中没有layout,那就逐级往上寻找layout,直到匹配到app/layout.tsx。
plaintext
app/
├── (marketing)/ --> 带括号,是路由组,继续往下找
│ └── page.tsx --> 对应路径 "/"
│
├── blog/ --> 对应路径 "/blog"
│ └── page.tsx --> 找到目标,但是当前文件夹里面没有layout.tsx
│
└── Layout.tsx --> 如果blog上级文件夹中有layout.tsx,那就用这个layout.tsx来渲染blog/page.tsx
二、Page------页面的业务内容
Layout.tsx负责当前页面的结构,通常里面的代码都是没有复杂业务逻辑的静态纯组件,承担业务逻辑的都是Page.tsx。
Page有params和searchParams两个默认参数。params用于获取 动态路由 (Dynamic Routes)中的参数。例如,如果你的文件路径是 app/blog/[slug]/page.tsx,那么 params 就会包含 slug。 searchParams用于获取 URL 中 问号后面的查询参数 (Query Parameters)。例如 ?query=nextjs&page=1:
tsx
const Page = async({
params,
searchParams
}:{
params:Promise<{slug:string}>,
searchParams:Promise<{[key: string]:string | string[] | undefined}>
}) =>{
const {slug} = await params;
const urlParams = await searchParams;
console.log(slug, urlParams);
return <>
<Nav />
<p>Hello, I'm the blog page</p>
</>
}
export default Page
当访问/blog/a?query=11111&query=222222&b=5时,console会输出:
其中['a']是只有访问动态路由才会有输出,如果访问一个静态路由地址,params输出就是undefined,searchParams则会以键值对的形式展示出来
三、路由组划分多根模板
nextjs通过(folder)的方式划分路由组,路由组本身并不会被next识别为路由,比如文件结构如果是/app/(marketing)/blog/page.tsx,那么只需要访问/blog就能访问到这个page.tsx。
路由组虽然不会被识别为路由,但由于上面提到的page"从内而外"匹配layout渲染的机制,不同的模块都可以有自己的rootlayout:
plaintext
app/
├── (marketing)/ --> marketing模块对应路由组
│ └── page.tsx --> 对应路径 "/"
| └── layout.tsx --> marketing模块下所有page的根layout
|
├── (dashboard)/ -->
│ └── dashboard/
│ └── page.tsx --> 对应路径 "/dashboard"
│ └── layout.tsx --> dashboard模块下所有page的根layout