はじめに
ファイルを選択するフォームがある際、
ドラッグ&ドロップができるとスマートで便利ですよね。
mulitiple属性がつくと複数のファイルを一つのフォームで送信が可能です。
そうした上でドラッグ&ドロップで選択する仕様にするのはさほど難しくはありませんでした。
しかし、複数同時にドロップするのではなく、
その複数のファイルを一個ずつドロップできるようにしたかったのですが...
ちょっとツマってしまったので、その解決方法をメモ。
実装
<form action="~~~" accept-charset="~~~" method="post">
<input multiple="multiple" type="file" name="task_images" id="task_images">
<div id="dropZone" style="width:~~~px;height:~~~px;">
ここにドラッグ&ドロップ
</div>
<input type="submit">
</form>
"~~~~"やname="task_images"は例です。
ここでは扱うファイルを画像ファイルを想定してます。
idの"task_images" "dropZone"でそれぞれの要素を取得していきます。
var fileField = document.getElementById('task_images');
var dropZone = document.getElementById('dropZone');
var dt = new DataTransfer();
dropZone.addEventListener('drop', (e)=>{
e.preventDefault();
dt.items.add(e.dataTransfer.files[0]);
fileField.files = dt.files;
});
dtに代入されたDataTransferオブジェクトはドラッグ&ドロップされたデータを扱う、保持するために使われます。
なお、safariとIEはnewに対応していないので注意!
e.preventDefault();がないとドロップできないので大事です。
dt.itemsはDataTransferItemListオブジェクト
dt.filesとe.dataTransfer.filesはFileListオブジェクトです。
e.dataTransfer.files[0]はFileオブジェクトです。
非常にややこしい!
e.dataTransfer.filesにはドロップされたファイル(Fileオブジェクト)がFileListオブジェクトの中に同時にドロップされた数だけ格納されています。
今回は一つずつドロップし選択するのでe.dataTransfer.files[0]をaddメソッドでdt.itemsに追加します。
そうするとdt.filesにFileListオブジェクトとして変更が反映されています。
最後にinputエレメントであるfileFieldのfilesをdt.filesに差し替えます。
これでドロップによってinputのファイル選択を追加していくことができます。
最後に
DataTransferにはclearData()など応用の利くメソッドがあるので、
使いようによってはファイル数の制限も実装できます。
画像プレビューにも使うこともできるので、ぜひ調べて見てください。
参考
DataTransfer
Document: drop イベント
FileListは作れる!~file inputの中身も自由自在~