文章索引及分頁

渲染文章索引列表

#

從前面的文章中,我們已經知道如何渲染一篇文章,接下來只要如法泡製,就能建立一個索引頁面列出部落格中所有的文章了。

personal-blog/pages/blog/index.js
import Container from '@module/essence/components/Container'
import Heading from '@module/essence/components/Heading'
import { getPosts } from '../../utils/post'
const BlogPostIndexPage = ({ posts }) => {
return (
<Container>
{posts.map((post) => (
<Link key={post.slug} fluid href={`/blog/${post.slug}`}>
<Heading size="m">{post.frontMatter.title}</Heading>
</Link>
))}
</Container>
)
}
export const getStaticProps = ({ params }) => {
return {
props: {
posts: getPosts()
},
}
}
export default BlogPostIndexPage

分頁處理

#

當文章數量不多時,或許唯一的索引頁面是一個可行的做法,但隨著部落格的經營,文章只會增加不會減少,如果文章數量達到某個規模時,勢必要採取某些方法讓這個索引頁面不要過度膨脹。目前這個階段,我傾向使用分頁來管理,因為對於讀者來說,仍然有辦法透過前往不同的分頁來瀏覽完所有文章。如果文章再成長到下一個規模時,或許就要捨棄分頁,改用關鍵字搜尋了,但分頁機制對於目前的部落格規模來說已經十分足夠!

我的實作方式是建立每一個分頁的路由頁面,並且擴充 utility functions 以支援分頁計算。

  1. 路由

    personal-blog/pages/blog/page/[pageId].js
    import Container from '@module/essence/components/Container'
    import Heading from '@module/essence/components/Heading'
    import Label from '@module/essence/components/Label'
    import { getPosts, getPostsByPageSizeAndPageId } from '../../../utils/post'
    const BlogPostIndexPage = ({ posts, pagination }) => {
    return (
    <Container>
    {posts.map((post) => (
    <Link key={post.slug} fluid href={`/blog/${post.slug}`}>
    <Heading size="m">{post.frontMatter.title}</Heading>
    </Link>
    ))}
    <Label size="m">
    {pagination.pageId}頁,共{pagination.pageCount}
    </Label>
    </Container>
    )
    }
    export async function getStaticPaths() {
    const BLOG_PAGE_SIZE = 10
    const posts = await getPosts()
    const pageCount = Math.ceil(posts.length / BLOG_PAGE_SIZE)
    return {
    paths: Array(pageCount)
    .fill(0)
    .map((_, pageIndex) => {
    const pageId = `${pageIndex + 1}`
    return {
    params: {
    pageId,
    },
    }
    }),
    fallback: false, // can also be true or 'blocking'
    }
    }
    export const getStaticProps = ({ params }) => {
    const BLOG_PAGE_SIZE = 10
    const posts = getPosts()
    const pageCount = Math.ceil(posts.length / BLOG_PAGE_SIZE)
    const { pageId } = params
    const currentPagedPosts = getPostsByPageSizeAndPageId(BLOG_PAGE_SIZE, pageId)
    return {
    props: {
    posts: currentPagedPosts,
    pagination: {
    pageSize: BLOG_PAGE_SIZE,
    pageCount,
    pageId,
    },
    },
    }
    }
    export default BlogPostIndexPage
  2. 分頁計算 utility functions

    只要能夠知道所有文章的數量,以及每頁文章數量,就能進行分頁計算,或是拿到屬於特定頁面的文章列表,此外,我還打算使用文章發佈日期進行排序。因此我們可以在 utility functions 實作 兩個函數:

    personal-blog/utils/post.js
    export const getPosts = () => {
    // ...
    }
    export const getSortedPosts = () => {
    const posts = getPosts()
    const sortedPosts = posts.sort((a, b) => {
    if (a.frontMatter.publishDate < b.frontMatter.publishDate) {
    return 1
    } else if (a.frontMatter.publishDate > b.frontMatter.publishDate) {
    return -1
    } else {
    return 0
    }
    })
    return sortedPosts
    }
    export const getPostsByPageSizeAndPageId = (pageSize, pageId) => {
    const sortedPosts = getSortedPosts()
    const offset = pageSize * (parseInt(pageId) - 1)
    return sortedPosts.slice(offset, offset + pageSize)
    }

如此一來,我們基本上已經滿足一個部落格所需要的最低功能了:

  • 編輯者可以撰寫 MDX 文章檔案
  • 讀者可以瀏覽具有分頁的文章列表
  • 讀者可以點選特定文章並且瀏覽全文

相信讀者們也已具備足夠的知識,可以開始動手客製出自己的部落格,展開屬於自己的旅程了!關於功能性的講解在此先告一段落,後續文章將會開始介紹偏向營運層面以及閱讀體驗的功能,歡迎有興趣繼續鑽研的朋友一起看下去。