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

在Gatsby单篇文章中实现上/下一篇链接的技术问询

实现文章上一篇/下一篇链接的最优方案

不需要手动在frontmatter中添加id字段,Gatsby会自动为每个MDX节点生成唯一id,结合日期排序就能实现上一篇/下一篇链接,以下是两种可行方案:

方案一:组件内处理所有文章数据(推荐,逻辑直观)

修改GraphQL查询,同时获取当前文章和所有其他文章的列表,在组件中通过索引定位前后篇:

1. 更新页面查询

export const query = graphql`
  query ($id: String) {
    # 获取当前文章详情,保留原始date用于排序比较
    currentPost: mdx(id: {eq: $id}) {
      frontmatter {
        title
        date(formatString: "MMMM D, YYYY")
        slug
        date
      }
      id
    }
    # 获取所有文章,按发布日期倒序排列,排除当前文章
    allPosts: allMdx(
      sort: {frontmatter: {date: DESC}}
      filter: {id: {ne: $id}}
    ) {
      nodes {
        frontmatter {
          title
          slug
        }
        id
      }
    }
  }
`;

2. 组件内计算前后篇

export default function PostPage({ data }) {
  const { currentPost, allPosts } = data;
  const posts = allPosts.nodes;
  // 找到当前文章在列表中的位置
  const currentIndex = posts.findIndex(post => post.id === currentPost.id);

  // 上一篇:列表中当前文章的前一项(若存在)
  const prevPost = currentIndex > 0 ? posts[currentIndex - 1] : null;
  // 下一篇:列表中当前文章的后一项(若存在)
  const nextPost = currentIndex < posts.length - 1 ? posts[currentIndex + 1] : null;

  return (
    <div className="post-page">
      <h1>{currentPost.frontmatter.title}</h1>
      <p className="post-date">{currentPost.frontmatter.date}</p>
      {/* 渲染文章内容 */}
      <div className="post-nav">
        {prevPost && (
          <a href={`/${prevPost.frontmatter.slug}`}>
            ← {prevPost.frontmatter.title}
          </a>
        )}
        {nextPost && (
          <a href={`/${nextPost.frontmatter.slug}`}>
            {nextPost.frontmatter.title} →
          </a>
        )}
      </div>
    </div>
  );
}

方案二:GraphQL直接筛选前后篇(适合大数量文章)

通过GraphQL的filter和sort直接查询出前后篇,减少前端处理的数据量:

1. 更新页面查询

需要在createPage时将文章的date传入页面context,确保$date变量能被查询获取:

export const query = graphql`
  query ($id: String, $date: Date) {
    currentPost: mdx(id: {eq: $id}) {
      frontmatter {
        title
        date(formatString: "MMMM D, YYYY")
        slug
      }
    }
    # 上一篇:发布时间早于当前文章的最新一篇
    prevPost: mdx(
      filter: {frontmatter: {date: {lt: $date}}, id: {ne: $id}}
      sort: {frontmatter: {date: DESC}}
      limit: 1
    ) {
      frontmatter {
        title
        slug
      }
    }
    # 下一篇:发布时间晚于当前文章的最早一篇
    nextPost: mdx(
      filter: {frontmatter: {date: {gt: $date}}, id: {ne: $id}}
      sort: {frontmatter: {date: ASC}}
      limit: 1
    ) {
      frontmatter {
        title
        slug
      }
    }
  }
`;

注:需在gatsby-node.js的createPage方法中,将文章的frontmatter.date添加到context中。

2. 组件中直接使用查询结果

export default function PostPage({ data }) {
  const { currentPost, prevPost, nextPost } = data;

  return (
    <div className="post-page">
      <h1>{currentPost.frontmatter.title}</h1>
      <p className="post-date">{currentPost.frontmatter.date}</p>
      {/* 渲染文章内容 */}
      <div className="post-nav">
        {prevPost && (
          <a href={`/${prevPost.frontmatter.slug}`}>
            ← {prevPost.frontmatter.title}
          </a>
        )}
        {nextPost && (
          <a href={`/${nextPost.frontmatter.slug}`}>
            {nextPost.frontmatter.title} →
          </a>
        )}
      </div>
    </div>
  );
}

方案优势

  • 无需手动维护id字段,避免人工输入错误
  • 依赖Gatsby自动生成的节点id或文章slug(确保slug唯一)作为标识,可靠性更高
  • 排序逻辑可灵活调整(比如按标题、更新时间等)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 16:27:43