Tube - Basic Layout

  • Image组件
    <Image
      src="/logo.svg"
      width={50}
      height={50}
      alt="Logo"
    />
    
    • Image 组件来自 Next.js,默认开启懒加载
    • widthheight 默认是 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;
    
  • 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
    // 当前目录结构
    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>
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容