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

如何在Next.js中正确处理带动态路由的无/1后缀SSG分页?

实现无/1后缀的分类SSG分页方案

你可以通过抽离共用渲染组件+拆分路由文件的方式实现需求,既不用复制代码,也能保持URL的简洁性,具体步骤如下:

1. 抽离共用页面模板

先把分类页面的渲染逻辑封装成独立组件,所有路由页面都复用这个组件来渲染内容,避免代码重复。

创建components/CategoryContent.jsx:

export default function CategoryContent({ category, currentPage, posts, totalPages }) {
  return (
    <div>
      <h1>分类:{category}</h1>
      <div className="posts-list">
        {posts.map(post => (
          <article key={post.id}>{post.title}</article>
        ))}
      </div>
      <div className="pagination">
        {currentPage > 1 && (
          <a href={`/${category}`}>上一页</a>
        )}
        {Array.from({ length: totalPages }, (_, i) => i + 1).map(page => (
          <a
            key={page}
            href={page === 1 ? `/${category}` : `/${category}/${page}`}
            className={currentPage === page ? 'active' : ''}
          >
            {page}
          </a>
        ))}
        {currentPage < totalPages && (
          <a href={`/${category}/${currentPage + 1}`}>下一页</a>
        )}
      </div>
    </div>
  )
}

2. 处理分类首页(无page后缀)

创建pages/[category]/index.jsx,这个文件对应/category-one、/category-two这类首页路径,默认获取第1页的数据:

import CategoryContent from '../../components/CategoryContent'

export async function getStaticPaths() {
  // 假设你从API或数据库获取所有分类列表
  const categories = ['category-one', 'category-two']
  
  return {
    paths: categories.map(category => ({
      params: { category }
    })),
    fallback: false // 若需要动态生成未预定义的分类,可改为'blocking'或true
  }
}

export async function getStaticProps({ params }) {
  const { category } = params
  const page = 1 // 首页默认第1页
  
  // 这里替换成你获取分类第1页数据的逻辑
  const posts = await fetchPostsByCategory(category, page)
  const totalPages = await getTotalPagesForCategory(category)

  return {
    props: {
      category,
      currentPage: page,
      posts,
      totalPages
    }
  }
}

export default function CategoryIndexPage(props) {
  return <CategoryContent {...props} />
}

3. 处理分页页面(带page后缀)

创建pages/[category]/[page].jsx,对应/category-one/2、/category-two/3这类路径,处理page>=2的情况:

import CategoryContent from '../../components/CategoryContent'

export async function getStaticPaths() {
  const categories = ['category-one', 'category-two']
  const paths = []

  // 为每个分类生成2及以上的分页路径,这里假设每个分类最多有3页
  categories.forEach(category => {
    for (let page = 2; page <= 3; page++) {
      paths.push({
        params: { category, page: page.toString() }
      })
    }
  })

  return { paths, fallback: false }
}

export async function getStaticProps({ params }) {
  const { category, page } = params
  const currentPage = parseInt(page, 10)

  // 验证page有效性,避免非法路径
  if (currentPage < 2) {
    return { notFound: true }
  }

  // 获取对应分页的数据
  const posts = await fetchPostsByCategory(category, currentPage)
  const totalPages = await getTotalPagesForCategory(category)

  // 如果请求的页数超过总页数,返回404
  if (currentPage > totalPages) {
    return { notFound: true }
  }

  return {
    props: {
      category,
      currentPage,
      posts,
      totalPages
    }
  }
}

export default function CategoryPage(props) {
  return <CategoryContent {...props} />
}

关键说明

  • 两个路由文件都复用同一个CategoryContent组件,仅在数据获取逻辑(getStaticPaths和getStaticProps)上做区分,完全避免代码重复。
  • 首页默认对应page=1,无需在URL中添加/1后缀,符合你的需求。
  • 分页页面仅处理page>=2的情况,非法的page参数(比如1或超过总页数)会返回404,保证路由的合法性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 09:35:22