ブログ

Blog

コンクリートに刻まれた矢印

Astroのサイトにページ番号付きのページネーションを実装する方法

Astroで構築している当サイトのブログに「1.2.3…」などの数字形式で表示されるのページネーションを実装しました。ほとんど公式の手順に従っただけですが、うまくいったので備忘録的に残しておきます。

「前へ」「次へ」のページ送りを表示させる

まずは投稿一覧ページにページ送りを表示させるコードの全体像です。

src/pages/blog/[...page].astro
---
// 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関数を返しています。

src/pages/blog/[...page].astro
---
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プロパティを使用することができます。

src/pages/blog/[...page].astro
---
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記載の通りでうまくいきます。

src/pages/blog/[...page].astro
---
// 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として、pageurlPatternを渡しています。この2つのpropsは必須です。

また任意のpropsであるpreviousLabelを指定することで、前へ(次へ)のラベルを変更することができます。ラベル自体を非表示にすることも可能です。

表示・非表示のロジックを追加

最後に2ページ目以降がある場合にのみPaginationコンポーネントを表示するようにします。

src/pages/blog/[...page].astro
---
// 次のページが存在するかを判定する定数
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で実装するよりは自分にとってはまだハードルが高いかなという印象です。

参考サイト