You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为NextJS静态Markdown博客列表添加分页?

Next.js 静态Markdown博客分页实现方案

针对你的需求,以下是修复并优化后的分页实现方案,解决原代码中的逻辑问题并适配Next.js App Router的SSG规则:

一、重构元数据获取函数

先拆分原函数,将「获取所有文章元数据」和「分页筛选」逻辑分离,避免重复读取文件,提升代码复用性:

// @/components/ReusableComponents/createPaginationMetaData.ts
import fs from "fs";
import matter from "gray-matter";

export interface PostMetadata {
    slug: string;
    data: any;
}

// 获取所有Markdown文章的元数据
export const getAllPostMetadata = (path: string): PostMetadata[] => {
  const files = fs.readdirSync(path);
  const markdownPosts = files.filter((file) => file.endsWith(".md"));

  return markdownPosts.map((fileName) => {
    const fileContents = fs.readFileSync(`${path}/${fileName}`, "utf8");
    const matterResult = matter(fileContents);
    return {
      slug: fileName.replace(".md", ""),
      data: matterResult.data,
    };
  });
};

// 根据分页参数筛选对应页的文章
export const getPaginatedPosts = (
  posts: PostMetadata[],
  currentPage: number,
  postsPerPage: number
): PostMetadata[] => {
  const startIndex = (currentPage - 1) * postsPerPage;
  return posts.slice(startIndex, startIndex + postsPerPage);
};

二、修改博客列表分页页面

更新app/blog/[page].tsx,修复总页数计算错误,替换原生跳转为Next.js客户端导航组件:

// app/blog/[page].tsx
import React from "react";
import Link from "next/link";
import { getAllPostMetadata, getPaginatedPosts, PostMetadata } from "@/components/ReusableComponents/createPaginationMetaData";

const POSTS_PER_PAGE = 10; // 每页展示文章数

// 生成所有分页页面的静态参数
export async function generateStaticParams() {
  const allPosts = getAllPostMetadata("blog");
  const totalPages = Math.ceil(allPosts.length / POSTS_PER_PAGE);

  return Array.from({ length: totalPages }, (_, index) => ({
    page: `${index + 1}`,
  }));
}

// 为每个分页页面生成SEO标题
export async function generateMetadata({ params }: { params: { page: string } }) {
  const currentPage = parseInt(params.page, 10) || 1;
  return {
    title: `博客列表 - 第 ${currentPage} 页`,
  };
}

export default function BlogList({ params }: { params: { page: string } }) {
  const currentPage = parseInt(params.page, 10) || 1;
  const allPosts = getAllPostMetadata("blog");
  const totalPages = Math.ceil(allPosts.length / POSTS_PER_PAGE);
  const posts = getPaginatedPosts(allPosts, currentPage, POSTS_PER_PAGE);

  // 渲染文章预览
  const postPreviews = posts.map((post) => (
    <div key={post.slug} style={{ marginBottom: "1.5rem" }}>
      <h3>{post.data.article_body.content.heading.t_title}</h3>
    </div>
  ));

  // 渲染分页控件
  const paginationControls = (
    <div style={{ marginTop: "2rem", display: "flex", gap: "1rem", alignItems: "center" }}>
      {currentPage > 1 && (
        <Link href={`/blog/${currentPage - 1}`} style={{ padding: "0.5rem 1rem", border: "1px solid #eee" }}>
          上一页
        </Link>
      )}
      <span>第 {currentPage} / {totalPages} 页</span>
      {currentPage < totalPages && (
        <Link href={`/blog/${currentPage + 1}`} style={{ padding: "0.5rem 1rem", border: "1px solid #eee" }}>
          下一页
        </Link>
      )}
    </div>
  );

  return (
    <div style={{ maxWidth: "800px", margin: "2rem auto", padding: "0 1rem" }}>
      {postPreviews}
      {paginationControls}
    </div>
  );
}

关键修改说明

  1. 函数拆分:将原getPostMetadata拆分为两个函数,避免重复读取文件,同时让分页逻辑更清晰
  2. 总页数计算修复:原代码中用当前页文章数计算总页数的逻辑错误,现在直接基于所有文章数计算
  3. 客户端导航优化:用Next.js的Link组件替换原生a标签,实现无刷新页面跳转
  4. SEO优化:添加generateMetadata函数为每个分页页面生成独立标题
  5. 静态参数生成:generateStaticParams正确生成所有分页页面的静态路由参数,确保SSG正常生成所有页面

内容的提问来源于stack exchange,提问作者manggae

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 10:33:33