M
← 文章列表
·3 分钟阅读·827Next.js学习笔记

Next.js App Router 核心特性

文件系统路由、特殊文件约定、generateStaticParams 静态生成、Metadata API——搭博客必须掌握的 Next.js 特性。

Next.js App Router 核心特性

Next.js 13+ 引入了 App Router,这是目前推荐的开发方式。本文介绍搭建博客过程中用到的几个核心特性。

1. 文件系统路由

App Router 基于 app/ 目录,文件路径就是 URL 路径

app/
  page.tsx              → /
  about/
    page.tsx            → /about
  posts/
    page.tsx            → /posts
    [slug]/
      page.tsx          → /posts/:slug  (动态路由)
  tags/
    [tag]/
      page.tsx          → /tags/:tag
  layout.tsx            → 所有页面共享的布局

[slug] 里的方括号表示这是个动态路由参数,访问 /posts/hello-world 时,slug 的值就是 "hello-world"

2. 特殊文件约定

在任意路由目录下,Next.js 识别这些特殊文件名:

文件名 作用
page.tsx 页面组件,URL 可访问
layout.tsx 布局,包裹子页面,切换页面时不会重新渲染
loading.tsx 页面加载中时显示的 UI(自动配合 Suspense)
error.tsx 页面报错时显示的 UI
not-found.tsx 调用 notFound() 时显示的 404 页面

博客里用到了 layout.tsx(放 Header/Footer)和通过 notFound() 触发的 404。

3. 动态路由页面的类型写法

Next.js 15+ 中,paramsPromise 类型,需要 await

// app/posts/[slug]/page.tsx

interface PageProps {
  params: Promise<{ slug: string }>;
}

export default async function PostPage({ params }: PageProps) {
  const { slug } = await params; // 必须 await
  const post = await getPostBySlug(slug);
  return <article>{post.title}</article>;
}

4. generateStaticParams:静态预生成

博客文章是静态内容,构建时就能生成好所有 HTML,不需要每次请求都重新生成。generateStaticParams 告诉 Next.js 有哪些动态路由需要预生成:

// 告诉 Next.js:预先生成这些路径
// /posts/hello-world
// /posts/typescript-basics
// /posts/nextjs-core-features
// ...
export async function generateStaticParams() {
  const slugs = getAllSlugs(); // 读取所有文章的 slug
  return slugs.map((slug) => ({ slug }));
  // 返回:[{ slug: "hello-world" }, { slug: "typescript-basics" }, ...]
}

优点: 所有文章页面在构建时就生成为静态 HTML,访问速度极快,对 SEO 非常友好。

5. Metadata API:动态 SEO

Next.js 提供了 generateMetadata 函数,自动为每个页面生成 <head> 里的 SEO 标签:

// 静态 metadata(适合不变的页面)
export const metadata = {
  title: "关于我",
  description: "关于这个博客",
};

// 动态 metadata(适合需要根据数据生成的页面,比如文章详情)
export async function generateMetadata({ params }: PageProps) {
  const { slug } = await params;
  const post = await getPostBySlug(slug);

  return {
    title: post.title,           // → <title>文章标题</title>
    description: post.excerpt,  // → <meta name="description" ...>
  };
}

layout.tsx 里设置了 template,子页面的标题会自动套上格式:

// layout.tsx
export const metadata = {
  title: {
    default: "Mary's Blog",
    template: "%s | Mary's Blog",  // %s 被子页面标题替换
  },
};

// 文章页设置 title: "TypeScript 入门"
// 最终浏览器标签显示:TypeScript 入门 | Mary's Blog

6. notFound():触发 404

访问不存在的文章时,调用 notFound() 渲染 404 页面:

import { notFound } from "next/navigation";

export default async function PostPage({ params }: PageProps) {
  const { slug } = await params;

  let post;
  try {
    post = await getPostBySlug(slug);
  } catch {
    notFound(); // 找不到文章,触发 404
  }

  return <article>{post.title}</article>;
}

如果目录下有 not-found.tsx,会渲染那个组件;否则用 Next.js 默认的 404 页面。


这五个特性是 App Router 的核心,把它们组合起来就构成了整个博客的路由和数据层。