無限スクロールは、ユーザーがページを下にスクロールするたびに新しいコンテンツを動的にロードする手法です。
これにより、ページ全体を一度に読み込む必要がなくなり、パフォーマンスが向上します。
従来、無限スクロールの実装には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とサーバーサイドの処理を連携させることで、高速で洗練された無限スクロールを実装できます。
この記事で紹介したテクニックを活用し、さらに発展させることで、ユーザーエンゲージメントを高める魅力的な無限スクロールを作成しましょう。