【フロントエンド入門23】ファイルアップロードとプレビュー機能の実装|ユーザーに使いやすいUI

ファイルアップロードは、Webアプリケーションでユーザーが画像やドキュメントをアップロードする際によく使われる機能です。これにプレビュー機能を追加することで、ユーザーがアップロードしたファイルの内容を確認でき、より使いやすいUIを提供できます。本記事では、ファイルアップロードとプレビュー機能の基本的な実装方法を初心者にもわかりやすく解説します。

ファイルアップロードの基本

HTMLによる基本的なファイル入力フォーム

ファイルアップロードを実装するには、まずHTMLでファイル選択用のフォームを作成します。

<form id="uploadForm">
  <label for="fileInput">ファイルを選択してください:</label>
  <input type="file" id="fileInput" name="file">
  <button type="submit">アップロード</button>
</form>

フォーム送信の基本動作

  1. ユーザーがファイルを選択して送信すると、選択したファイルがサーバーに送信されます。
  2. サーバー側でファイルを受け取り、保存または処理を行います。

ただし、現代のWebアプリケーションでは、ページをリロードせずにファイルをアップロードし、プレビューを表示する動作が一般的です。これにはJavaScriptを使って非同期処理を実装します。

JavaScriptを使ったファイルアップロードとプレビュー

非同期アップロードの概要

JavaScriptのfetchXMLHttpRequestを使えば、ページをリロードすることなくファイルをアップロードできます。また、選択したファイルをプレビュー表示することで、ユーザーに直感的なフィードバックを提供します。

1. 基本的なHTML構造

<form id="uploadForm">
  <label for="fileInput">画像を選択してください:</label>
  <input type="file" id="fileInput" name="file" accept="image/*">
  <button type="submit">アップロード</button>
</form>

<div id="previewContainer">
  <p>プレビュー:</p>
  <img id="imagePreview" src="" alt="プレビュー画像" style="display:none; width: 200px;">
</div>

2. プレビュー機能のJavaScriptコード

const fileInput = document.getElementById('fileInput');
const imagePreview = document.getElementById('imagePreview');

fileInput.addEventListener('change', function() {
  const file = this.files[0];

  if (file) {
    const reader = new FileReader();

    reader.onload = function(event) {
      imagePreview.src = event.target.result;
      imagePreview.style.display = 'block';
    };

    reader.readAsDataURL(file);
  }
});

解説

  • FileReaderオブジェクト:選択したファイルを読み込み、データURLとして取得します。
  • reader.onload:ファイルが読み込まれた後に実行される処理です。画像プレビューのsrc属性に読み込んだデータを設定します。

非同期でファイルをサーバーにアップロード

1. 非同期送信のJavaScriptコード

const uploadForm = document.getElementById('uploadForm');

uploadForm.addEventListener('submit', async function(event) {
  event.preventDefault(); // デフォルトのフォーム送信を防ぐ

  const formData = new FormData(uploadForm);

  try {
    const response = await fetch('https://example.com/upload', {
      method: 'POST',
      body: formData
    });

    if (response.ok) {
      alert('ファイルが正常にアップロードされました!');
    } else {
      alert('アップロードに失敗しました。');
    }
  } catch (error) {
    console.error('エラー:', error);
    alert('ネットワークエラーが発生しました。');
  }
});

解説

  • FormDataオブジェクト:フォームの入力データを簡単に収集して送信できます。
  • fetch関数:非同期でサーバーにデータを送信するために使用します。
  • エラーハンドリング:ネットワークエラーやサーバーエラーに対応するための処理を追加しています。

ファイルタイプやサイズのバリデーション

バリデーションの重要性

セキュリティや正確なデータ処理のため、アップロードするファイルのタイプやサイズを事前にチェックすることが重要です。

例:JavaScriptによるバリデーション

fileInput.addEventListener('change', function() {
  const file = this.files[0];

  if (file) {
    // ファイルタイプのチェック
    if (!file.type.startsWith('image/')) {
      alert('画像ファイルを選択してください。');
      this.value = ''; // 入力をリセット
      return;
    }

    // ファイルサイズのチェック (2MB以下)
    if (file.size > 2 * 1024 * 1024) {
      alert('ファイルサイズは2MB以下にしてください。');
      this.value = '';
      return;
    }

    // プレビュー表示(前述のコード)
    const reader = new FileReader();
    reader.onload = function(event) {
      imagePreview.src = event.target.result;
      imagePreview.style.display = 'block';
    };
    reader.readAsDataURL(file);
  }
});

解説

  • file.type:ファイルのMIMEタイプを取得し、画像かどうかを判定します。
  • file.size:ファイルサイズをバイト単位で取得し、2MB以下であるかを確認します。

アップロードの進捗表示

進捗バーを表示するHTML

<div id="progressContainer" style="display: none;">
  <progress id="uploadProgress" value="0" max="100"></progress>
</div>

進捗表示のJavaScriptコード

uploadForm.addEventListener('submit', function(event) {
  event.preventDefault();
  const formData = new FormData(uploadForm);

  const xhr = new XMLHttpRequest();
  xhr.open('POST', 'https://example.com/upload');

  xhr.upload.addEventListener('progress', function(event) {
    if (event.lengthComputable) {
      const percentComplete = (event.loaded / event.total) * 100;
      document.getElementById('uploadProgress').value = percentComplete;
      document.getElementById('progressContainer').style.display = 'block';
    }
  });

  xhr.onload = function() {
    if (xhr.status === 200) {
      alert('アップロードが完了しました!');
    } else {
      alert('アップロードに失敗しました。');
    }
    document.getElementById('progressContainer').style.display = 'none';
  };

  xhr.send(formData);
});

解説

  • XMLHttpRequest:アップロード進捗を追跡するために使用します。
  • xhr.upload.addEventListener('progress'):アップロードの進行状況をリアルタイムで取得し、プログレスバーに反映します。

結論

ファイルアップロードとプレビュー機能を組み合わせることで、ユーザーにとって直感的で使いやすいインターフェースを提供できます。また、バリデーションや進捗表示を追加することで、セキュリティとユーザー体験の向上を両立させることができます。