0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Astro.js 記事一覧でページネーションを導入する

Last updated at Posted at 2025-04-17

ブログの記事数が増えてくると、一覧ページが長くなってしまいます。ページネーションを導入すれば、ページを分割して表示でき、ユーザー体験が向上します。ここでは、Astroの paginate 機能を使って、記事一覧ページに1ページあたり5件表示のページネーションを実装する手順を紹介します。

ページネーション実装手順

1.動的ルートファイルを作成 (src/pages/blog/[...page].astro)**

  • もし既に記事一覧ページがあれば、そのファイル(例えば src/pages/blog/index.astro)を 削除 するか、別の名前に変更してください。(例: index-old.astro
  • 次に、src/pages/blog/ ディレクトリ内に [...page].astro という名前で 新しいファイルを作成 します。このファイルが /blog/, /blog/2, /blog/3, ... といったページをすべて処理します。
your-project/
└── src/
    ├── content/
    │   └── blog/
    ├── pages/
    │   ├── blog/
    │   │   └── [...page].astro <-- これを新規作成
    │   ├── tags/
    │   └── [...slug].astro (個別記事ページ)
    └── layouts/

2.getStaticPaths でページ分割を定義

作成した src/pages/blog/[...page].astro ファイルを開き、フロントマター部分 (--- 内) に getStaticPaths 関数を実装します。ここでAstroの paginate 関数を使ってページ分割を行います。

---
// src/pages/blog/[...page].astro
import { getCollection } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro'; // 適切なレイアウトを指定

export async function getStaticPaths({ paginate }) {
  // 1. 'blog'コレクションの記事をすべて取得
  const allPosts = await getCollection('blog');

  // 2. 公開日 (pubDate) の新しい順に記事をソート (ページ分割する前にソートする)
  const sortedPosts = allPosts.sort((a, b) =>
    b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
  );

  // 3. paginate関数でページ分割 (1ページあたり5件)
  //    ソート済みの記事リストを渡す
  return paginate(sortedPosts, { pageSize: 5 });
}

// paginateから渡された現在のページ情報を受け取る
const { page } = Astro.props;

// 個別記事ページへのURLを生成するヘルパー関数 (他ページで使っているものを流用)
function getPostUrl(post) {
  if (post.data.url) {
    return `/${post.data.url}/`;
  }
  return `/blog/${post.slug}/`;
}
---
  • getStaticPaths は引数として { paginate } を受け取ります。
  • getCollection('blog') で全記事を取得し、必要に応じて sort() で並び替えます(重要: paginate する前にソートしてください)。
  • paginate(sortedPosts, { pageSize: 5 }) を呼び出します。第1引数に記事データの配列、第2引数の pageSize に1ページあたりの表示件数を指定します。これが各ページのパスとデータを自動生成してくれます。
  • const { page } = Astro.props; で、現在のページに関する情報(記事データ、URLなど)を受け取ります。

3.ページネーションされた記事リストの表示

[...page].astro のHTMLテンプレート部分で、page.data(現在のページの記事リスト)を使って記事を表示します。

---
// --- 上記のフロントマターコード ---
---
<BaseLayout title={`ブログ記事一覧 - ${page.currentPage}ページ目`}>
  <h1>ブログ記事一覧</h1>
  <p>{page.start + 1}件目から{page.end + 1}件目を表示 ({page.total}件中)</p>

  <ul>
    {/* page.data に現在のページの5件分の記事が入っている */}
    {page.data.map((post) => (
      <li>
        <a href={getPostUrl(post)}>{post.data.title}</a>
        <span style="font-size: 0.8em; margin-left: 8px;">
          ({post.data.pubDate.toLocaleDateString()})
        </span>
      </li>
    ))}
  </ul>
</BaseLayout>
  • Astro.props から受け取った page オブジェクトを使います。
  • page.data が現在のページに表示すべき記事(最大5件)の配列なので、これを map() でループして表示します。
  • page.currentPage (現在のページ番号)、page.total (全記事数) なども表示に利用できます。
  • 個別記事へのリンクは、これまで通り getPostUrl ヘルパー関数などで生成します。

4.ページネーションリンクの表示

記事リストの下などに、「前へ」「次へ」のナビゲーションリンクを追加します。page.url.prevpage.url.next を使います。

---
// --- 上記のフロントマターコード & 記事リスト表示コード ---
---
<BaseLayout title={`ブログ記事一覧 - ${page.currentPage}ページ目`}>
  {/* ... 記事リスト ... */}

  {/* ↓ ここからページネーションリンクを追加 */}
  <nav aria-label="ページネーション">
    {/* 前のページへのリンク (page.url.prevが存在する場合のみ表示) */}
    {page.url.prev ? (
      <a href={page.url.prev}>&larr; 前のページへ</a>
    ) : (
      <span>&larr; 前のページへ</span> // リンク無効表示 (任意)
    )}

    <span style="margin: 0 1em;">
      {page.currentPage} / {page.lastPage} ページ
    </span>

    {/* 次のページへのリンク (page.url.nextが存在する場合のみ表示) */}
    {page.url.next ? (
      <a href={page.url.next}>次のページへ &rarr;</a>
    ) : (
      <span>次のページへ &rarr;</span> // リンク無効表示 (任意)
    )}
  </nav>
  {/* ↑ ここまでページネーションリンク */}
</BaseLayout>
  • page.url.prev が存在すれば「前のページへ」のリンクを表示します。最初のページでは undefined になります。
  • page.url.next が存在すれば「次のページへ」のリンクを表示します。最後のページでは undefined になります。
  • 現在のページ番号 (page.currentPage) と総ページ数 (page.lastPage) を表示すると分かりやすいです。

開発サーバーで確認

ターミナルで開発サーバーを起動します。

npm run dev
# または pnpm dev, yarn dev

ブラウザで以下のURLにアクセスして確認してみましょう。

  • 1ページ目: http://localhost:4321/blog/
  • 2ページ目: http://localhost:4321/blog/2
  • 3ページ目: http://localhost:4321/blog/3

各ページに記事が5件ずつ表示され、「前へ」「次へ」のリンクが正しく機能し、最後のページでは「次へ」が、最初のページでは「前へ」がリンク切れ(または非表示)になっていれば完了です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?