快適なメディア閲覧体験を作る!クライアントサイド・ページネーションと高機能モーダルのUI/UX実装
快適なメディア閲覧体験を作る!クライアントサイド・ページネーションと高機能モーダルのUI/UX実装
ソースコード: https://github.com/hayate-hu6/local-media-viewer.git
はじめに
開発の途中で数千枚の画像を一度にブラウザに表示させるとメモリを圧迫し、スクロールも重くなることに気付きました。これを解決するために「ページネーション(ページ分割)」を実装しました。 また、一覧画面のサムネイルをクリックしたときに拡大表示する「モーダルウィンドウ」も、画像ビューアーには欠かせない機能です。
今回は、これらを標準のJavaScriptでどのように実装し、ユーザー体験(UX)を高めているか解説します。
クライアントサイド・ページネーション
通常、ページネーションは「DBから10件だけ取得する」といったサーバーサイドでの処理が一般的です。しかし今回は、全ファイルリストをすでにJSONとして持っているため、クライアントサイド(ブラウザ側)で配列をスライスして表示する方法を採用しています。
const PAGE_SIZE = 100; // 1ページ100件
function renderPage(page) {
// ...範囲チェック(省略)...
const start = (currentPage - 1) * PAGE_SIZE;
const end = Math.min(start + PAGE_SIZE, filteredFiles.length);
const pageItems = filteredFiles.slice(start, end);
// ...描画処理...
}
Array.prototype.slice(start, end) を使うだけで、現在のページに必要なデータだけを切り出せます。サーバーへの再リクエストが発生しないため、ページ切り替えは爆速です。これが全件取得方式のメリットです。
UI連動
ページ番号の変更に合わせて、次へ/前へボタンの有効・無効化も制御しています。
pagePrevBtns.forEach(btn => btn.disabled = currentPage === 1);
pageNextBtns.forEach(btn => btn.disabled = currentPage === totalPages);
また、 document.querySelector('main').scrollTop = 0; を呼び出すことで、ページを切り替えたときに自動的に一番上までスクロールするようにしており、ユーザビリティに配慮しています。
モーダルウィンドウの実装
サムネイルをクリックすると、画面全体を覆うオーバーレイ(モーダル)が表示され、オリジナルサイズの画像や動画が表示されます。
HTML構造
<div id="media-modal" class="hidden">
<!-- 閉じるボタンなど -->
<div id="media-container">
<!-- ここに img や video タグが入る -->
</div>
</div>
CSSで position: fixed で全画面に配置し、.hidden クラスの着脱で表示制御を行います。
コンテンツの動的生成
function updateModalContent() {
const item = filteredFiles[currentModalIndex];
mediaContainer.innerHTML = ''; // クリア
if (item.type === 'video') {
const video = document.createElement('video');
video.controls = true;
video.src = item.url;
mediaContainer.appendChild(video);
video.play().catch(e => {}); // 自動再生
} else {
const img = document.createElement('img');
img.src = item.url;
mediaContainer.appendChild(img);
}
}
currentModalIndex という状態変数を使って「今何番目のファイルを表示しているか」を管理しています。「次へ」ボタンが押されたらインデックスをインクリメントし、updateModalContent を呼ぶだけで画像が切り替わります。
キーボードショートカット対応
マウス操作だけでなく、キーボードでも快適に操作できるようにイベントリスナーを設定しています。
document.addEventListener('keydown', (e) => {
if (!modal.classList.contains('hidden')) {
if (e.key === 'Escape') closeModal(); // Escで閉じる
if (e.key === 'ArrowLeft') showPrevMedia(); // ←で前へ
if (e.key === 'ArrowRight') showNextMedia(); // →で次へ
}
});
この数行があるだけで、操作感は劇的に向上し、デスクトップアプリのような使い心地になります。
UX向上のための工夫: Videoホバー再生
一覧画面で動画ファイルを見つけるとき、いちいちクリックして再生するのは面倒です。そこで、マウスを乗せたときだけプレビュー再生する機能を実装しています。
if (item.type === 'video') {
// ...
card.addEventListener('mouseenter', () => { visual.play().catch(() => { }); });
card.addEventListener('mouseleave', () => { visual.pause(); });
}
mouseenter で play(), mouseleave で pause() するだけのシンプル実装ですが、これによりユーザーは「中身を確認しながら探す」ことができるようになります。
※ただし、大量の動画を一斉にロードすると重くなるため、preload="metadata" を設定して通信量を抑える工夫もしています。
まとめ
ページネーションとモーダルは、大量のコンテンツを扱うアプリにおけるUIの要です。
- 配列操作による高速ページネーション: サーバー負荷ゼロでサクサク動作
- キーボード対応: プロフェッショナルな操作感
- ホバー再生: 直感的なブラウジング体験
これらを丁寧に実装することで、単なる「ファイル置き場」から「メディアギャラリー」へと品質を高めることができました。
次回は最終回、ブラウザ非対応の動画形式問題に立ち向かう「FFmpeg自動変換スクリプト」の解説です。
次回: Node.jsのchild_processとFFmpegで作る!非対応動画ファイルのMP4自動一括変換ツール
同シリーズ記事
- 第1回:Node.jsとExpressで構築するローカルメディアビューアー:プロジェクト構成と全体アーキテクチャ
- 第2回:Node.js Expressによるセキュアなメディア配信サーバーの構築手法と実装の全貌
- 第3回:DB不要!Node.js CryptoモジュールとHttpOnly Cookieで実現する安全な簡易認証システム
- 第4回:Node.jsで数千ファイル規模のディレクトリツリーを高速に解析する再帰アルゴリズムの実装
- 第5回:React不要!標準JavaScriptで実装する軽量SPAの状態管理と高速DOM操作テクニック
- 第6回:快適なメディア閲覧体験を作る!クライアントサイド・ページネーションと高機能モーダルのUI/UX実装
- 第7回:Node.jsのchild_processとFFmpegで作る!非対応動画ファイルのMP4自動一括変換ツール