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,提问作者Лео
相关产品推荐
相关产品推荐

