htmxによる無限スクロールによるコンテンツの動的ロード

htmxによる無限スクロールによるコンテンツの動的ロード プログラミング

無限スクロールは、ユーザーがページを下にスクロールするたびに新しいコンテンツを動的にロードする手法です。
これにより、ページ全体を一度に読み込む必要がなくなり、パフォーマンスが向上します。

従来、無限スクロールの実装にはJavaScriptによる複雑な処理が必要でした。
しかし、htmxを使えばシンプルなHTMLの属性だけで実現できます。

この記事では、htmxを使った無限スクロールの実装方法を詳しく解説します。

本記事の内容

  • 無限スクロールのHTML構造
  • コンテンツの動的ロード
  • ローディングインジケータの表示
  • コンテンツの終わりの検出
  • サンプルコード
  • まとめ

それでは、上記に沿って解説していきます。

無限スクロールのHTML構造

htmxについてよくわからない場合は、次の記事からご覧ください。

まず、無限スクロールのHTML構造を定義します。
コンテンツを表示するコンテナと、新しいコンテンツをロードするトリガー要素を以下のように配置します。

<div id="content-container">
  <!-- 初期コンテンツ -->
  <div class="item">Initial Item #1</div>
  <div class="item">Initial Item #2</div>
  <div class="item">Initial Item #3</div>

  <div id="load-trigger" hx-get="load_content.php?page=1" hx-trigger="revealed" hx-target="#content-container" hx-swap="beforeend">
    <span class="loading-indicator">Loading...</span>
  </div>
</div>

#load-trigger要素には、hx-get、hx-trigger、hx-target、hx-swapの属性を設定します。
hx-triggerを”revealed”にすることで、要素が画面内に表示された時点でトリガーが発火します。

hx-getで指定したPHPファイルからコンテンツを取得し、hx-targetで指定したコンテナの最後に追加します。

コンテンツの動的ロード

次に、PHPを使ってコンテンツを動的に生成します。
load_content.phpというPHPファイルを作成し、以下のようなコードを記述します。

<?php
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
$items_per_page = 10;
$total_items = 100;

$start_index = ($page - 1) * $items_per_page;
$end_index = min($start_index + $items_per_page, $total_items);

for ($i = $start_index; $i < $end_index; $i++) {
  echo "<div class='item'>Item #{$i}</div>";
}

// コンテンツの終わりを検出
if ($end_index < $total_items) {
  echo "<div id='load-trigger' hx-get='load_content.php?page=" . ($page + 1) . "' hx-trigger='revealed' hx-target='#content-container' hx-swap='beforeend'>
          <span class='loading-indicator'>Loading...</span>
        </div>";
} else {
  echo "<div id='end-of-content' class='hidden' hx-swap='outerHTML'>コンテンツの終わりに達しました。</div>";
}
?>

このPHPファイルでは、ページ番号に基づいてコンテンツを生成しています。
$total_items変数で全アイテム数を定義し、1ページあたりのアイテム数を$items_per_page変数で指定します。

生成したコンテンツの最後に、次のコンテンツをロードするための#load-trigger要素を追加します。
ただし、$end_indexが$total_itemsに達した場合は、次のコンテンツがないことを意味することになります。

そのため、代わりに#end-of-content要素を追加します。
この要素は、class=’hidden’を持ち、初期状態では非表示になります。

htmxは、#load-trigger要素が画面内に表示されたときに、load_content.phpを再度呼び出して新しいコンテンツを取得します。
コンテンツの終わりが検出された場合、#end-of-content要素が表示されます。

ローディングインジケータの表示

無限スクロールでは、新しいコンテンツのロード中にローディングインジケータを表示すると良いでしょう。
以下のようなCSSを使って、ローディングインジケータを実装します。

.loading-indicator {
  display: none;
}

.loading-indicator.htmx-indicator {
  display: inline-block;
}

htmx-indicatorクラスは、htmxがAjaxリクエストを開始したときに要素に追加されます。
これを利用して、ローディングインジケータの表示/非表示を切り替えます。

コンテンツの終わりの検出

無限スクロールを実装する際、コンテンツの終わりを検出して適切に処理することが重要です。
PHPコードでは、$end_indexが$total_itemsに達した場合、#end-of-content要素を追加します。

// コンテンツの終わりを検出
if ($end_index < $total_items) {
  echo "<div id='load-trigger' hx-get='load_content.php?page=" . ($page + 1) . "' hx-trigger='revealed' hx-target='#content-container' hx-swap='beforeend'>
          <span class='loading-indicator'>Loading...</span>
        </div>";
} else {
  echo "<div id='end-of-content'>コンテンツの終わりに達しました。</div>";
}

$end_indexが$total_itemsより小さい場合は、次のコンテンツをロードするための#load-trigger要素を追加します。
これにより、ユーザーがスクロールを続けると、次のコンテンツが動的にロードされます。

一方、$end_indexが$total_itemsに達した場合は、#end-of-content要素を追加します。
この要素には「コンテンツの終わりに達しました。」というメッセージが含まれており、コンテンツの終わりに達したことをユーザーに通知します。

 #end-of-content要素には、class=’hidden’やhx-swap=’outerHTML’などの属性は付与されていません。
これにより、コンテンツの終わりが検出された時点で、このメッセージが表示されるようになります。

htmxは、#load-trigger要素が画面内に表示されたときに、load_content.phpを再度呼び出して新しいコンテンツを取得します。
コンテンツの終わりが検出された場合、#load-trigger要素は追加されず、代わりに#end-of-content要素が表示されます。
これにより、無限スクロールが停止し、ユーザーにコンテンツの終わりを通知します。

サンプルコード

以上の内容を組み合わせた完全なサンプルコードは以下の通りです。

PHPコード (load_content.php)

<?php
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
$items_per_page = 10;
$total_items = 100;

$start_index = ($page - 1) * $items_per_page;
$end_index = min($start_index + $items_per_page, $total_items);

for ($i = $start_index; $i < $end_index; $i++) {
  echo "<div class='item'>Item #{$i}</div>";
}

// コンテンツの終わりを検出
if ($end_index < $total_items) {
  echo "<div id='load-trigger' hx-get='load_content.php?page=" . ($page + 1) . "' hx-trigger='revealed' hx-target='#content-container' hx-swap='beforeend'>
          <span class='loading-indicator'>Loading...</span>
        </div>";
} else {
  echo "<div id='end-of-content'>コンテンツの終わりに達しました。</div>";
}
?>

HTMLコード (index.html)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>無限スクロールによるコンテンツの動的ロード</title>
  <script src="https://unpkg.com/htmx.org@1.7.0"></script>
  <style>
    .loading-indicator {
      display: none;
    }

    .loading-indicator.htmx-indicator {
      display: inline-block;
    }

    .hidden {
      display: none;
    }
  </style>
</head>
<body>
  <div id="content-container">
    <!-- 初期コンテンツ -->
    <div class="item">Initial Item #1</div>
    <div class="item">Initial Item #2</div>
    <div class="item">Initial Item #3</div>

    <div id="load-trigger" hx-get="load_content.php?page=1" hx-trigger="revealed" hx-target="#content-container" hx-swap="beforeend">
      <span class="loading-indicator">Loading...</span>
    </div>
  </div>
</body>
</html>

このコードを実行すると、シンプルで高速な無限スクロールが実現されます。
コンテンツの終わりが検出された場合、「コンテンツの終わりに達しました。」というメッセージが表示されます。

まとめ

この記事では、htmxとPHPを組み合わせて無限スクロールを実装する方法を解説しました。
htmxのhx-trigger=”revealed”を使うことで、要素が画面内に表示されたタイミングでコンテンツの動的ロードをトリガーできます。

また、ローディングインジケータやエラーハンドリングを実装することで、ユーザーにとって使いやすいUIが作成できます。
さらに、コンテンツの終わりを検出し、適切に処理することで、無限スクロールが無限に続くことを防ぎます。

htmxとサーバーサイドの処理を連携させることで、高速で洗練された無限スクロールを実装できます。
この記事で紹介したテクニックを活用し、さらに発展させることで、ユーザーエンゲージメントを高める魅力的な無限スクロールを作成しましょう。

タイトルとURLをコピーしました