ドラッグ&ドロップは「マウスでつかんで、そのままブラウザに渡す入力方法」
ドラッグ&ドロップ(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.files に FileList が入ります。
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 で背景色を変えて、ユーザーに「今ここに乗ってるよ」と伝えるdrop で event.dataTransfer.files から File を取り出す
画像かどうかを file.type で軽くチェックURL.createObjectURL(file) で一時 URL を作り、img.src にセットしてプレビュー
という構成です。
ここまでできると、
「ドラッグ&ドロップで画像プレビュー」はほぼマスターです。
重要ポイント:dataTransfer には「ファイル以外」も入る
dataTransfer の中身のイメージ
drop イベントの event.dataTransfer は、
ドラッグ中のデータをまとめて持っているオブジェクトです。
ファイルがドロップされた場合は dataTransfer.files に FileList が入りますが、
テキストや 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 がそんなに大事なのか
dragover や drop で event.preventDefault() を呼ばないと、
ブラウザは「自分の標準動作」を優先します。
例えば、
画像ファイルをブラウザにドロップすると、
その画像を新しいタブで開こうとしたり、
ページ全体をその画像で置き換えたりします。
それを防いで、
「このイベントは自分の JavaScript で処理するから、
ブラウザは標準動作をしないでね」と伝えるのが preventDefault() です。
特に dragover での preventDefault は、
「ここはドロップ可能な領域だ」とブラウザに教える合図でもあるので、
ドラッグ&ドロップ実装の中で最重要と言っていいくらいの一行です。
window 全体でのドロップを無効化することもある
アプリによっては、
「画面のどこにドロップされても、ページ遷移などさせたくない」
ということがあります。
その場合は、window や document に対してもdragover / drop の preventDefault を仕込むことがあります。
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 が連発されるdragover で event.preventDefault() しないと drop が発火しないdrop イベントの event.dataTransfer.files から FileList を取得できる
ファイルを扱うときは、結局 File API / FileReader / Blob の世界につながる
視覚的なフィードバック(背景色を変えるなど)を付けると、UX が一気に良くなる
まずは次の 2 つを、自分の手で書いてみてください。
画像ファイルをドラッグ&ドロップしてプレビュー表示する
複数ファイルをドラッグ&ドロップして、名前とサイズの一覧を表示する
これがスムーズに書けるようになったとき、
ドラッグ&ドロップは単なる「かっこいい UI」ではなく、
「ユーザーの手の動きと、あなたの Web アプリを直結させる入力インターフェース」
として、かなり頼もしく感じられるはずです。
