Next.js 15【实用教程】2025最新版

发布于:2025-02-16 ⋅ 阅读:(30) ⋅ 点赞:(0)

官网 https://nextjs.org/docs/app/getting-started

Next.js 简介

Next.js 由 Vercel 开发和维护,旨在解决单页应用(SPA)和多页应用(MPA)在性能和 SEO 上的不足。

核心特性

  • 服务端渲染(SSR)-- 在服务器端预渲染页面,将 HTML 直接发送到客户端,从而提高了页面加载速度和 SEO 效果。
  • 静态生成(SSG)-- 在构建时生成 HTML 的方式,使得每个页面的内容都能在构建时生成并缓存,这样无需在每次请求时生成 HTML,从而显著提升页面性能。
  • 通过文件系统的结构快速创建页面路由。同时,API 路由功能使开发者能够直接在 Next.js 项目中创建后端 API
  • 增量静态再生成(ISR)-- 将部分页面静态化,并在内容更新时触发重新生成,以确保页面内容的新鲜度和快速访问。
  • 内置图像优化功能,可通过 <Image /> 组件自动进行图像懒加载、响应式优化和格式转换,有效减少加载时间并提升页面性能。
  • 对 CSS 模块、Sass 和 styled-jsx 原生支持,支持 Tailwind CSS 和其他流行的 CSS 框架

适用场景

  • 内容驱动的网站:如博客、新闻网站等,Next.js 的 SSG 和 ISR 特性使其在内容频繁更新时,能够保持高效的性能和良好的 SEO 表现。
  • 电商平台:对于电商网站,Next.js 的 SSR 和 ISR 能够确保页面快速响应,满足用户体验的需求,同时也便于动态加载产品信息。
  • Web应用:复杂的企业级应用或 SaaS 应用可以利用 Next.js 提供的 SSR、动态路由和 API 路由实现高性能的全栈架构。
  • 个人网站和组合展示:对于个人博客和作品展示,Next.js 提供了静态生成和图像优化功能,能够确保简洁高效的页面展示。

搭建开发环境,创建项目

  • 安装 Node.js
  • 创建项目
npx create-next-app@latest

在这里插入图片描述
在这里插入图片描述

会自动安装依赖

在这里插入图片描述

项目目录

  • src\app\page.tsx 项目首页
  • src\app\layout.tsx 页面布局
  • public 静态资源,例如图像、字体等

页面路由

会根据 src\app 内的文件自动创建,具体对应关系范例如下:

路由 文件路径
/ src\app\page.tsx
/blog src\app\blog\page.tsx
/blog/动态参数 src\app\blog\[slug]\page.tsx
  • 所有页面路由都对应一个 page.tsx
  • 含动态参数的路由,对应 [slug] 文件夹下的 page.tsx
app/
├── layout.jsx      // 布局组件
├── page.jsx        // 首页,映射到 "/"
├── about/
│   └── page.jsx    // 关于页面,映射到 "/about"
├── blog/
│   ├── layout.jsx  // 博客专属布局
│   └── [slug]/
│       └── page.jsx  // 动态路由,映射到 "/blog/:slug"
├── api/hello/
│   └── route.jsx   // API 路由,映射到 "/api/hello"
└── globals.css    // 全局样式

页面中获取路由动态参数的方法如下

export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;

  return (
    <>
      <h1>{slug} 篇博客的标题</h1>
      <p>{slug} 篇博客的内容</p>
    </>
  );
}
  • 页面函数组件的参数为 { params,}
  • 函数参数的类型为 { params: Promise<{ slug: string }>;},可见参数 params 是一个 Promise
  • 需用 await 同步获取到 params ,并解构出其中的 slug
  • 解构出的 slug 值即路由上的动态参数,以 /blog/1 为例,slug 的值为 1

路由跳转

Link

内置的 Link 组件,点击可实现路由跳转

import Link from "next/link";
 <Link href="/blog">板块--博客</Link>

页面布局

每个文件夹下的 layout.tsx 文件,即该文件夹对应路由的页面布局

布局 布局文件路径
全局布局 src\app\layout.tsx
/blog 的布局 src\app\blog\layout.tsx

以 blog 板块的布局为例,src\app\blog\layout.tsx 的内容为

export default function BlogLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <>
      <header>页头-博客板块</header>
      <section>{children}</section>
    </>
  );
}
  • BlogLayout 为任意自定义的布局函数名称
  • 函数的参数为 {children:children} , 简写为 {children}
  • 函数参数的类型为 {children:React.ReactNode}
  • 函数的返回内容需含有 {children} ,其他内容可任意自定义

服务端组件 vs 客户端组件

https://blog.csdn.net/weixin_41192489/article/details/145629124

内置方案

字体 next/font

https://blog.csdn.net/weixin_41192489/article/details/145625560

图片 Image

https://blog.csdn.net/weixin_41192489/article/details/145629598

样式 CSS

https://blog.csdn.net/weixin_41192489/article/details/145625489

后端服务

Next.js 不仅能构建前端页面,还同时提供了后端服务

src\app\api 内的 route.js 会自动生成后端接口

范例:src\app\api\blog\route.js

import { NextResponse } from "next/server";

// 处理 GET 请求
export async function GET(request) {
  // 这里可以编写从数据库或其他数据源获取用户数据的逻辑
  const data = [
    {
      id: 1,
      title: "第1篇博客的标题",
      content: "第1篇博客的内容",
    },
    {
      id: 2,
      title: "第2篇博客的标题",
      content: "第2篇博客的内容",
    },
  ];
  return NextResponse.json(data);
}

启动项目后,浏览器访问 http://localhost:3000/api/blog ,效果如下:

在这里插入图片描述

获取数据(访问接口)

https://blog.csdn.net/weixin_41192489/article/details/145632442

实战范例

在这里插入图片描述

src\app\page.tsx

import Link from "next/link";

export default function Page() {
  return (
    <>
      <h1>首页</h1>
      <div>
        <Link href="/blog">板块--博客</Link>
      </div>
      <div>
        <Link href="/note">板块--笔记</Link>
      </div>
    </>
  );
}

src\app\layout.tsx

import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
      >
        <header>页头--全局</header>
        {children}
      </body>
    </html>
  );
}

src\app\blog\page.tsx

在这里插入图片描述

import Link from "next/link";

interface blog {
  id: number;
  title: string;
  content: string;
}
export default async function Page() {
  const data = await fetch("http://localhost:3000/api/blog");

  const blogList = await data.json();

  return (
    <>
      <h1>博客列表</h1>
      <ul>
        {blogList.map((blog: blog) => (
          <li key={blog.id}>
            <Link href={`/blog/${blog.id}`}>{blog.title}</Link>
          </li>
        ))}
      </ul>
    </>
  );
}

src\app\blog\layout.tsx

export default function BlogLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <>
      <header>页头-博客板块</header>
      <section>{children}</section>
    </>
  );
}

src\app\blog[slug]\page.tsx

在这里插入图片描述

export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;

  return (
    <>
      <h1>{slug} 篇博客的标题</h1>
      <p>{slug} 篇博客的内容</p>
    </>
  );
}

src\app\api\blog\route.js

import { NextResponse } from "next/server";

// 处理 GET 请求
export async function GET(request) {
  // 这里可以编写从数据库或其他数据源获取用户数据的逻辑
  const data = [
    {
      id: 1,
      title: "第1篇博客的标题",
      content: "第1篇博客的内容",
    },
    {
      id: 2,
      title: "第2篇博客的标题",
      content: "第2篇博客的内容",
    },
  ];
  return NextResponse.json(data);
}

网站公告

今日签到

点亮在社区的每一天
去签到