Astroのサイトにページ番号付きのページネーションを実装する方法
Astroで構築している当サイトのブログに「1.2.3…」などの数字形式で表示されるのページネーションを実装しました。ほとんど公式の手順に従っただけですが、うまくいったので備忘録的に残しておきます。
「前へ」「次へ」のページ送りを表示させる
まずは投稿一覧ページにページ送りを表示させるコードの全体像です。
---// 1ページに表示する件数を設定export const postsPerPage = 8;
// getStaticPaths()で動的なルートを設定export async function getStaticPaths({ paginate }) { // 投稿を呼び出し const allPosts = await getCollection("blog");
// 投稿を新しい順に並び替え const sortedPosts = allPosts.sort((a, b) => { const aDate = new Date(a.data.pubDate); const bDate = new Date(b.data.pubDate); return bDate.getTime() - aDate.getTime(); });
// 並び替えた投稿の配列から、1ページにX記事づつ入るようにページを生成 return paginate(sortedPosts, { pageSize: postsPerPage });}
// paginate()関数を使用すると、各ページのデータはpageプロパティとして渡されるconst { page } = Astro.props;---
{page.url.prev ? <a href={page.url.prev}>前へ</a> : null}{page.url.next ? <a href={page.url.next}>次へ</a> : null}
ファイル名
公式サイトではファイル名が[page].astro
となっていますが、今回は[...page].astro
としています。レストパラメーターを使用することで深さに関係なくパスを生成することができます。
また[page].astro
では投稿一覧ページのパスは~/blog/1/
となってしまいますが、[...page].astro
では~/blog/
で表示することができます。
paginate関数
動的なルートを生成するgetStaticPaths関数の中でpaginate関数を返しています。
---export async function getStaticPaths({ paginate }) { const allPosts = await getCollection("blog");
const sortedPosts = allPosts.sort((a, b) => { const aDate = new Date(a.data.pubDate); const bDate = new Date(b.data.pubDate); return bDate.getTime() - aDate.getTime(); });
return paginate(sortedPosts, { pageSize: postsPerPage });}
paginate関数の引数には投稿の配列と、pageSize
プロパティを含むオブジェクトを渡しています。
pageSizeに数値を指定することで1ページあたりに表示する件数を変更することが可能です。今回は定数postsPerPage
を指定しています。
テンプレートでページ送りを出力
paginate関数を使用すると、各ページのデータが入ったpage
プロパティを使用することができます。
---const { page } = Astro.props;---
{page.url.prev ? <a href={page.url.prev}>前へ</a> : null}{page.url.next ? <a href={page.url.next}>次へ</a> : null}
pageプロパティの完全なAPIリファレンスは公式サイトに記載されています。 上記ではpage.url.prev
にアクセスして、前の(次の)ページのURLを出力しています。
ここまでで「前へ」「次へ」のページネーションの実装は完了です。
ページ番号付きの表記に変更する
次に「1.2.3…」などのページ番号付きのページネーションに変更します。
自前で実装しているコードも見かけましたが、今回は@philnash/astro-paginationという公式にも記載されているインテグレーションを使用しました。アクセシビリティにも配慮されていて良さそうです。
インテグレーションをインストール
npm
でインストールします。
npm install @philnash/astro-pagination
@philnash/astro-paginationの使用方法
基本的にはGithub記載の通りでうまくいきます。
---// astro-paginationコンポーネントを呼び出しimport Pagination from "@philnash/astro-pagination";type Props = { page: Page<CollectionEntry<"blog">>;};---
<Pagination page={page} urlPattern={"/blog/{}"} previousLabel="<" nextLabel=">" />
README.mdではimport { Pagination }
と名前付きインポートになっていましたが、私の場合デフォルトインポートに変更するとうまく機能しました。
Pagination
コンポーネントにはpropsとして、page
とurlPattern
を渡しています。この2つのpropsは必須です。
また任意のpropsであるpreviousLabel
を指定することで、前へ(次へ)のラベルを変更することができます。ラベル自体を非表示にすることも可能です。
表示・非表示のロジックを追加
最後に2ページ目以降がある場合にのみPagination
コンポーネントを表示するようにします。
---// 次のページが存在するかを判定する定数const hasNextPage = page.size < page.total ? true : false;---
{ hasNextPage && ( <div class="c-paginaiton"> <Pagination page={page} urlPattern={"/blog/{}"} previousLabel="<" nextLabel=">" /> </div> )}
page
プロパティのsizeとtotalを比較して2ページ目以降が存在するかを判定し、出力するHTMLを条件分岐しています。
以上でページ番号付きのページネーションの実装は完了です。Astroでは一般的なページネーションプロパティが用意されているのでとても簡単にページ送りを実装することができました。
簡単とはいえpaginate
関数やpage
プロパティをしっかりと理解しておかないといけないので、WordPressで実装するよりは自分にとってはまだハードルが高いかなという印象です。