JavaScript | Web API:ファイル・データ操作 - ドラッグ&ドロップ

JavaScript JavaScript
スポンサーリンク

ドラッグ&ドロップは「マウスでつかんで、そのままブラウザに渡す入力方法」

ドラッグ&ドロップ(D&D)は、
「ユーザーがファイルや要素をマウスでつかんで、別の場所に“落とす”操作をイベントとして扱う仕組み です。

ファイルアップロードでよくある、

「ここにファイルをドラッグ&ドロップしてください」

みたいな UI は、まさにこの仕組みを使っています。

ポイントは 2 つです。

ブラウザはドラッグ中・ドロップ時にイベントを発火してくれる
そのイベントの中から「何がドロップされたか(ファイルなど)」を取り出せる

この 2 つさえ押さえれば、
「ファイルをドロップしてプレビュー」「ドロップしてアップロード」などは、
そこまで難しくありません。


ドラッグ&ドロップの最小構成をまず押さえる

drop だけでは動かない:dragover での preventDefault が必須

ファイルをドロップで受け取りたい要素(ドロップゾーン)を用意します。

<div id="dropzone" style="width:300px;height:150px;border:2px dashed #666;display:flex;align-items:center;justify-content:center;">
  ここにファイルをドロップ
</div>

JavaScript の基本形はこうです。

const dropzone = document.querySelector("#dropzone");

dropzone.addEventListener("dragover", (event) => {
  event.preventDefault(); // これが超重要
});

dropzone.addEventListener("drop", (event) => {
  event.preventDefault();
  console.log("ドロップされました");
});
JavaScript

ここで一番大事なのは、
dragover イベントで event.preventDefault() を呼んでいることです。

これをしないと、
ブラウザは「ここにはドロップできない」と判断してしまい、
drop イベント自体が発火しません。

つまり、

「ドラッグ中に dragover で preventDefault する」
→ 「ここはドロップしていい場所だよ」とブラウザに伝える
→ だから drop イベントが飛んでくる

という流れになっています。

drop イベントからファイルを取り出す

ファイルがドロップされたとき、
drop イベントの event.dataTransfer.filesFileList が入ります。

dropzone.addEventListener("drop", (event) => {
  event.preventDefault();

  const files = event.dataTransfer.files; // FileList
  if (!files || files.length === 0) {
    console.log("ファイルはありません");
    return;
  }

  const file = files[0];
  console.log("ファイル名:", file.name);
});
JavaScript

ここでやっていることは、

event.dataTransfer.files から FileList を取得
中の File を取り出す
あとは File API / FileReader の世界

という、とても素直な流れです。


例題:ドラッグ&ドロップで画像ファイルを受け取り、プレビュー表示する

HTML

<div id="dropzone" style="width:300px;height:150px;border:2px dashed #666;display:flex;align-items:center;justify-content:center;margin-bottom:16px;">
  ここに画像ファイルをドロップ
</div>
<img id="preview" alt="プレビュー" style="max-width:300px;display:block;">

JavaScript

const dropzone = document.querySelector("#dropzone");
const preview = document.querySelector("#preview");

dropzone.addEventListener("dragover", (event) => {
  event.preventDefault();
  dropzone.style.backgroundColor = "#eef"; // 視覚的なフィードバック
});

dropzone.addEventListener("dragleave", () => {
  dropzone.style.backgroundColor = "";
});

dropzone.addEventListener("drop", (event) => {
  event.preventDefault();
  dropzone.style.backgroundColor = "";

  const files = event.dataTransfer.files;
  if (!files || files.length === 0) return;

  const file = files[0];
  if (!file.type.startsWith("image/")) {
    alert("画像ファイルをドロップしてください");
    return;
  }

  const url = URL.createObjectURL(file);
  preview.src = url;
});
JavaScript

ここでの流れを整理すると、

dragover で preventDefault して「ここはドロップOK」と宣言
dragleave / dragover で背景色を変えて、ユーザーに「今ここに乗ってるよ」と伝える
dropevent.dataTransfer.files から File を取り出す
画像かどうかを file.type で軽くチェック
URL.createObjectURL(file) で一時 URL を作り、img.src にセットしてプレビュー

という構成です。

ここまでできると、
「ドラッグ&ドロップで画像プレビュー」はほぼマスターです。


重要ポイント:dataTransfer には「ファイル以外」も入る

dataTransfer の中身のイメージ

drop イベントの event.dataTransfer は、
ドラッグ中のデータをまとめて持っているオブジェクトです。

ファイルがドロップされた場合は dataTransfer.filesFileList が入りますが、
テキストや HTML をドラッグした場合は dataTransfer.getData(...) で取り出せます。

例えば、別のページからテキストをドラッグしてきた場合など。

dropzone.addEventListener("drop", (event) => {
  event.preventDefault();

  const text = event.dataTransfer.getData("text/plain");
  console.log("テキスト:", text);
});
JavaScript

初心者のうちは、
「ファイルなら dataTransfer.files、テキストなら getData("text/plain")
くらいの理解で十分です。

ファイルアップロード用途では、
ほとんどの場合 dataTransfer.files だけ見ておけば OK です。


重要ポイント:ブラウザのデフォルト動作と戦わない

なぜ preventDefault がそんなに大事なのか

dragoverdropevent.preventDefault() を呼ばないと、
ブラウザは「自分の標準動作」を優先します。

例えば、
画像ファイルをブラウザにドロップすると、
その画像を新しいタブで開こうとしたり、
ページ全体をその画像で置き換えたりします。

それを防いで、
「このイベントは自分の JavaScript で処理するから、
ブラウザは標準動作をしないでね」と伝えるのが preventDefault() です。

特に dragover での preventDefault は、
「ここはドロップ可能な領域だ」とブラウザに教える合図でもあるので、
ドラッグ&ドロップ実装の中で最重要と言っていいくらいの一行です。

window 全体でのドロップを無効化することもある

アプリによっては、
「画面のどこにドロップされても、ページ遷移などさせたくない」
ということがあります。

その場合は、windowdocument に対しても
dragover / droppreventDefault を仕込むことがあります。

window.addEventListener("dragover", (event) => {
  event.preventDefault();
});

window.addEventListener("drop", (event) => {
  event.preventDefault();
});
JavaScript

これで、
意図しない場所へのドロップでページが吹き飛ぶ、
といった事故を防げます。


例題:ドラッグ&ドロップで複数ファイルを受け取り、一覧表示する

HTML

<div id="dropzone" style="width:300px;height:150px;border:2px dashed #666;display:flex;align-items:center;justify-content:center;margin-bottom:16px;">
  ここにファイルを複数ドロップ
</div>
<ul id="fileList"></ul>

JavaScript

const dropzone = document.querySelector("#dropzone");
const fileList = document.querySelector("#fileList");

dropzone.addEventListener("dragover", (event) => {
  event.preventDefault();
  dropzone.style.backgroundColor = "#eef";
});

dropzone.addEventListener("dragleave", () => {
  dropzone.style.backgroundColor = "";
});

dropzone.addEventListener("drop", (event) => {
  event.preventDefault();
  dropzone.style.backgroundColor = "";

  const files = event.dataTransfer.files;
  if (!files || files.length === 0) return;

  fileList.innerHTML = "";

  Array.from(files).forEach((file) => {
    const li = document.createElement("li");
    li.textContent = `${file.name} (${file.size} bytes)`;
    fileList.appendChild(li);
  });
});
JavaScript

ここでのポイントは、

Array.from(files) で FileList を配列っぽく扱っている
複数ファイルを一気に受け取り、名前とサイズを一覧表示している

というところです。

このパターンが書けると、
「ドラッグ&ドロップで複数ファイルを選ばせる UI」が
かなり現実的なレベルで実装できるようになります。


初心者として「ドラッグ&ドロップ」で本当に掴んでほしいこと

ドラッグ&ドロップは、
「イベントの流れ」と「dataTransfer の中身」を理解すれば怖くありません。

押さえてほしいポイントはこれです。

ドラッグ中には dragover が連発される
dragoverevent.preventDefault() しないと drop が発火しない
drop イベントの event.dataTransfer.files から FileList を取得できる
ファイルを扱うときは、結局 File API / FileReader / Blob の世界につながる
視覚的なフィードバック(背景色を変えるなど)を付けると、UX が一気に良くなる

まずは次の 2 つを、自分の手で書いてみてください。

画像ファイルをドラッグ&ドロップしてプレビュー表示する
複数ファイルをドラッグ&ドロップして、名前とサイズの一覧を表示する

これがスムーズに書けるようになったとき、
ドラッグ&ドロップは単なる「かっこいい UI」ではなく、
「ユーザーの手の動きと、あなたの Web アプリを直結させる入力インターフェース」
として、かなり頼もしく感じられるはずです。

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