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

SvelteKit Markdown博客实现上下篇文章导航功能求助

SvelteKit博客实现上下篇文章导航

现有代码基础

lib/utils/getPosts.js

// @ts-nocheck
export const getMarkdownPosts = async () => {
    const allPostFiles = import.meta.glob("/src/content/posts/*.md")
    const iterablePostFiles = Object.entries(allPostFiles)

    const allPosts = await Promise.all(
        iterablePostFiles.map(async ([path, resolver]) => {
            const { metadata } = await resolver()
            const postPath = path.split('/').at(-1)?.replace('.md', '')

            return {
                meta: metadata,
                path: postPath,
            }
        })
    )

    return allPosts
}

api/posts/+server.js(原始版本)

import { getMarkdownPosts } from '$lib/utils/getPosts'
import { json } from '@sveltejs/kit'

export const GET = async () => {
  const allPosts = await getMarkdownPosts()

  const sortedPosts = allPosts.sort((a, b) => {
    return new Date(b.meta.date) - new Date(a.meta.date)
  })

  return json(sortedPosts)
}

blog/[slug]/+page.js

export async function load({ params }){
    const post = await import(`../../../content/posts/${params.slug}.md`)
    const { title, date, categories, draft } = post.metadata
    const content = post.default

    return {
      content,
      title,
      date,
      categories
    }
}

你的修改尝试及问题

你尝试修改api/posts/+server.js为每篇文章添加上下篇关联,但不确定逻辑是否正确,也不知道如何在文章模板中使用这些数据:

import { getMarkdownPosts } from '$lib/utils/getPosts'
import { json } from '@sveltejs/kit'

export const GET = async () => {
  const allPosts = await getMarkdownPosts()

  //const notDraftPosts = allPosts.filter(post => post.meta.draft === false)

  const sortedPosts = allPosts.sort((a, b) => {
    return new Date(b.meta.date) - new Date(a.meta.date)
  }).map((post, index, allPosts) => ({
    ...post,
    next: allPosts[index - 1] || 0,
    previous: allPosts[index + 1] || 0,
}));

  return json(sortedPosts)
}

解决方案

1. 修正上下篇关联逻辑

你的思路是对的,但有两处可以优化:

  • 用null代替0作为无上下篇的标记,更符合语义
  • 边界判断更严谨:第一篇文章没有上一篇,最后一篇没有下一篇

修改后的api/posts/+server.js:

import { getMarkdownPosts } from '$lib/utils/getPosts'
import { json } from '@sveltejs/kit'

export const GET = async () => {
  const allPosts = await getMarkdownPosts()
  // 过滤草稿文章(如果需要)
  const publishedPosts = allPosts.filter(post => post.meta.draft !== true)
  
  const sortedPosts = publishedPosts.sort((a, b) => {
    return new Date(b.meta.date) - new Date(a.meta.date)
  }).map((post, index, posts) => ({
    ...post,
    // 最新的文章没有下一篇(next是更晚的文章)
    next: index > 0 ? posts[index - 1] : null,
    // 最早的文章没有上一篇(previous是更早的文章)
    previous: index < posts.length - 1 ? posts[index + 1] : null,
  }));

  return json(sortedPosts)
}

2. 在文章页面加载函数中获取上下篇数据

不需要通过API请求,直接在blog/[slug]/+page.js中调用getMarkdownPosts,这样更高效:

import { getMarkdownPosts } from '$lib/utils/getPosts'

export async function load({ params }){
    // 获取当前文章内容
    const post = await import(`../../../content/posts/${params.slug}.md`)
    const { title, date, categories, draft } = post.metadata
    const content = post.default

    // 获取所有已发布文章并排序
    const allPosts = await getMarkdownPosts()
    const publishedPosts = allPosts.filter(post => post.meta.draft !== true)
    const sortedPosts = publishedPosts.sort((a, b) => new Date(b.meta.date) - new Date(a.meta.date))

    // 找到当前文章在排序后的索引
    const currentIndex = sortedPosts.findIndex(post => post.path === params.slug)
    
    // 获取上下篇文章
    const nextPost = currentIndex > 0 ? sortedPosts[currentIndex - 1] : null
    const prevPost = currentIndex < sortedPosts.length - 1 ? sortedPosts[currentIndex + 1] : null

    return {
      content,
      title,
      date,
      categories,
      nextPost,
      prevPost
    }
}

3. 在文章模板中渲染上下篇导航

修改blog/[slug]/+page.svelte,添加导航模块:

<script>
    export let data
    import { dateFormat } from '$lib/utils/dateFormat.js';
</script>

<svelte:head>
  <title>My blog - {data.title}</title>
  <meta property="og:title" content={data.title} />
</svelte:head>

<article>
    <h1>{ data.title }</h1>
    {#if data.categories.length}
    <ul>
        {#each data.categories as category}
          <li>
            <a href="/blog/category/{category}">
              {category}
            </a>
          </li>
        {/each}
      </ul>
    {/if}
    <p>Published: {dateFormat(data.date)}</p>
    <svelte:component this={data.content} />
</article>

<!-- 上下篇导航 -->
<div class="post-navigation">
  {#if data.prevPost}
    <div class="prev-post">
      <a href="/blog/{data.prevPost.path}">
        <span>← 上一篇</span>
        <p>{data.prevPost.meta.title}</p>
      </a>
    </div>
  {/if}
  
  {#if data.nextPost}
    <div class="next-post">
      <a href="/blog/{data.nextPost.path}">
        <span>下一篇 →</span>
        <p>{data.nextPost.meta.title}</p>
      </a>
    </div>
  {/if}
</div>

<style>
.post-navigation {
  display: flex;
  justify-content: space-between;
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid #eee;
}

.post-navigation a {
  text-decoration: none;
  color: inherit;
}

.prev-post, .next-post {
  max-width: 45%;
}

.post-navigation span {
  font-size: 0.9rem;
  color: #666;
}

.post-navigation p {
  margin: 0.5rem 0 0;
  font-weight: 500;
}
</style>

说明

  • 过滤草稿文章:如果你的博客有草稿功能,记得保留publishedPosts的过滤逻辑,避免草稿文章出现在导航中
  • 上下篇定义:这里的nextPost是比当前文章更新的文章,prevPost是更早的文章,符合博客常见的导航逻辑
  • 样式可以根据你的博客风格自行调整

内容的提问来源于stack exchange,提问作者Лео

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 03:54:59