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 和我們前幾篇所定義的
blog
Collection 綁定,在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/
中加入四篇文章就能看看分頁的效果。