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