Astro 架站筆記(四):文章列表的分頁,淺談路由、排序及分頁
當文章數量多到一定的程度(幾十篇、上百篇)時,在瀏覽文章列表時通常就要考慮分頁了。
這是因爲就如部落格這類內容導向的網站,人們決定是否要閱讀全文,除了標題可能不太足夠,因此當加上文章的摘要或前言後,要把數十篇「標題加摘要」的文章塞入一個列表內,會顯得資訊量太大。
除了對讀者的資訊量過大,將所有文章摘要塞入一個頁面,一次要下載的內容量也會過大,進而導致載入速度慢,甚至無法載入成功。因此,今天就來聊聊文章列表的排序及分頁功能!
靜態及動態路由(Static and Dynamic Routes)
在聊分頁之前,我們先看看 Astro 定義路由的方式:由於 Astro 採用 File-based Routing,因此我們在 src/pages 下的內容會自動對應到網站中的一個 URL,這稱作 Static routes,靜態路由。
相對於靜態路由,另外一種路由方式稱作 Dynamic routes,動態路由。我們在上一講中提到的 src/pages/blog/[id].astro 中的 [id] 就是設定 Dynamic routes 的方式,而被中括號所包起來的 id 就是 URL 中的參數。
使用的方式就類似上一篇談到建立 src/pages/blog/[id].astro,中的內容:
1 | --- |
Astro 會根據 getStaticPaths() 所回傳的 Array 來建立數個 URLs,以上述例子來說會建立兩個頁面 /blog/1 和 /blog/2。
而程式碼下方的 Astro 模板則可透過 Astro.params 和 Astro.props 來取得 URL 的參數和內容。
排序
理解完了基本的靜態和動態路由,我們再來看看排序。
假設我們的部落格文章有 publishedTime 的資訊,格式如 2025-05-18 12:23:56,是個可以直接用 String 來比較時間先後順序的格式,那麼在取得一個 Collections 之後就能直接呼叫 JavaScript 原生的 sort() 函式,將最新的文章放在前面:
新增 src/pages/blog/index.astro
1 | --- |
如此一來,在文章總覽 /blog 中,就會按照新文章在最上面的排序來呈現。
分頁
再來看看這次的重點 Pagination,分頁的使用方式,在我們上面寫的 src/pages/blog/index.astro 中所顯示的文章列表僅有一個頁面而已,為了要達成分頁的目的,首先得將路由改成動態的方式,所以讓我們先將原本 blog/index.astro 中的內容調整後,建立以下檔案:
src/pages/blog/[page].astro
1 | --- |
從原本的一頁顯示所有文章,到使用動態路由產出能分頁的文章列表,有程式碼中標註的三點主要改動。
在
getStaticPaths({ paginate })的第一個參數當中,取出paginate()這個函式原本的回傳值由單純回傳文章的 Array 改成回傳一個
paginate(posts, { pageSize: 3 })呼叫後產生的物件,呼叫時需要傳原本的posts這個 Array,第二個參數稱作options,我們在此設定每頁的數量,為了測試方便我們挑了一個小數字3,然而比較常見的數字會是10左右最後,透過
Astro.props,我們可以取得每個頁面的資訊(Page Prop),包含currentPage(當前頁碼)、lastPage(最後頁碼)、url(一個羅列不同 URL 的物件,底下包含current、prev、next、first、last)等等,以及其他先不在這邊贅述的資訊。這邊值得一提的是,若要將 Page 和我們前幾篇所定義的
blogCollection 綁定,在Astro.props的型別中使用,可以先用type Props = { ... }或 Interface 來定義 Component Props,在使用的時候 Astro 就會自動將此型別和Astro.props所連結。
在最後 frontmatter 的最後我們獲得的了 posts 的 Array, currentPage, lastPage 和 url,用這些資訊就可以將分頁版本的文章列表 blog/[page].astro 所完成,以下是模板的部分:
1 | <html> |
在 <title> 部分,加上了現在所在的頁碼(currentPage),而導航的區塊則透過 url.prev 和 url.next 加入「上一頁」、「下一頁」,以及 lastPage 最後一頁頁碼來顯示「共幾頁」。
到目前為止,差一小步就完成分頁的開發了,當我們進入文章列表時,URL 的進入點通常是不含頁碼的,也就是 /blog 本身,但在有分頁的情況,我們預設應該要顯示第一頁(/blog/1)。
因此,只要在進入 /blog 這個 URL 的時候能夠自動導頁即可,可以在 Astro 設定檔中加入 redirects 的定義:
astro.config.cjs
1 | import { defineConfig } from 'astro/config'; |
在重新導向時 Astro 會預設使用 HTTP Status Code 301 而非 302,是因為 301 表示永久導向(而 302 是暫時),這通常在 SEO 時會更有利一些。
另外,還記得我們有個 src/pages/blog/index.astro 的檔案嗎?目前 SSG 的模式下我們想要導頁的話需要用上述解法,但在 SSR(Server Side Rendering)的模式下可以將其改成 return Astro.redirect('/blog/1');,也能達到同樣的效果。
然而在 SSG 之下,修改 astro.config.cjs 後就要記得將 blog/index.astro 給刪除。

在測試上,由於我們 pageSize 設定為 3,只要在 src/content/blog/ 中加入四篇文章就能看看分頁的效果。