Tube - Basic Layout
2025-08-01 本文已影响0人
章丸丸
-
Image组件
<Image src="/logo.svg" width={50} height={50} alt="Logo" />- Image 组件来自 Next.js,默认开启懒加载
-
width和height默认是 required -
src可以是 internal path 或者 external url,使用 external url 时需要在 next.config.js 文件中配置remotePatterns
import type { NextConfig } from "next"; const nextConfig: NextConfig = { images: { remotePatterns: [ // uploadthing 的图片 { protocol: 'https', hostname: 'szxu79mai4.ufs.sh' } ] } }; export default nextConfig; -
修改字体 src/app/layout.tsx
- 删除原有字体,导入新字体
import { Inter } from "next/font/google";,并修改<body>的className
- 删除原有字体,导入新字体
...
import { Inter } from "next/font/google";
...
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "New Tube",
description: "New Tube",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body
className={ inter.className }
>
{children}
</body>
</html>
);
}
-
App Router folders
- Next.js 15 使用
app/目录结构创建路由,路由基于文件夹结构自动生成
src/ app/ page.tsx // 根路径 "/" layout.tsx // 根布局,作用于所有页面 home/ page.tsx // "/home" videos/ [videoId]/ page.tsx // 动态路由 "/videos/:[videoId]"- 关于在动态路由中获取url参数,Next.js 15已将其修改为异步,无需手动传递,会从当前url中自动解析,具体文档可参考 Dynamic APIs are Asynchronous,在我们当前使用的服务器组件中可以用如下办法获取参数:
// 将params声明为一个Promise类型 interface VideoIdPageProps{ params: Promise<{ videoId: string }>; } const Page = async ({ params }: VideoIdPageProps) => { // 通过await获取异步参数 const { videoId } = await params; return ( <div> video ID: { videoId } </div> ) } export default Page; - Next.js 15 使用
-
Layout.tsx
- 在 App Router 中用于构建页面布局的组件,通常也用于创建可重用的布局(导航、侧边栏等),所以所有子页面会嵌套在 layout.tsx 的结构中
- 子文件夹可以有自己的 layout.tsx
- 如下目录结构中,会先渲染 app/layout.tsx,再渲染 app/videos/layout.tsx
- 必须包含
children作为插槽,children是页面内容
// 目录结构 src/ app/ page.tsx layout.tsx // 根布局 videos/ page.tsx layout.tsx // 子路由自己的layout [videoId]/ page.tsx // 动态路由 "/videos/:[videoId]"// app/videos/layout.tsx interface LayoutProps { children: React.ReactNode; } const Layout = ({ children }: LayoutProps) => { return ( <div> <div className="p-4 bg-red-300 w-full"> this is a navbar </div> { children } </div> ) } export default Layout; -
Route Groups
- 用()包裹的路由文件夹,路由分组,点解此处查看文档Route Groups
- 不会影响 url 路径结构,只是用来组织文件、复用布局或逻辑
// 当前目录结构 src/ app/ layout.tsx // 根布局 (home)/ layout.tsx page.tsx modules/ home/ ui/ layouts/ home-layout.tsx -
关于项目结构
- 基于上面的目录,app 文件夹中只放置 route 相关的文件
- 其他components、hooks、apis、server、utils等等都将放在 modules 文件夹下
-
Sidebar组件
-
SidebarProvider是根级组件,用于提供侧边栏的上下文 - 将其他组件写在
SidebarProvider内部,保证这些组件都能访问到其提供的有关状态 -
<SidebarMenuButton>默认渲染一个button,但使用了asChild就可以渲染成<SidebarMenuButton>包裹的组件了
<SidebarMenuButton tooltip={item.title} asChild isActive={false} onClick={e => { }} > <Link href={item.url} className="flex items-center gap-4"> <item.icon /> <span className="text-sm">{item.title}</span> </Link> </SidebarMenuButton> -