きっかけ
ブラウザからサーバーにファイルをアップロードする際、アップロードするファイルをPCのファイラーからブラウザへドラッグ・アンド・ドロップすることで行えるようにしようとしたら、何故かそのイベントハンドラの引数がDragEventになっていなかった。その原因と、対策について
状況
コードは下記
https://jsfiddle.net/kkotaro0111/8dsv37xu/5/
//with jQuery 2.x
$(function(){
var $f = $("#fileinput");
var $d = $("#dragarea");
var $c = $("#clickarea");
$f.on("change", function(){
handleFiles(this.files);
});
$c.on("click", function(e){
if( $f.length > 0 ){
$f.click();
}
e.preventDefault();
});
$d.on("dragenter", function(e){
e.stopPropagation();
e.preventDefault();
});
$d.on("dragover", function(e){
e.stopPropagation();
e.preventDefault();
});
$d.on("drop", function(e){
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer; // dt is undefined
var files = dt.files; // ここでエラー出る
handleFiles(files);
});
});
function handleFiles(files){
console.log("files", files);
}
input#fileinput[type='file']
#dragarea
button#clickarea
|ファイルを追加する
#fileinput
display: none
#dragarea
padding: 40px
border: 2px dashed #666
border-radius: 6px
動作について
このページを開き、点線エリアにファイルをドラッグ・アンド・ドロップすると、e
がjQuery.Event
クラスのインスタンスになっている。ドラッグ・アンド・ドロップされたファイルは、DragEvent
クラスのインスタンスが持つdataTransfer.files
プロパティから取得するのだが、jQuery.Event
にはこのプロパティが含まれていない。
原因
クラス名を見て分かる通り、jQueryは本来起きるEvent
をjQuery.Event
でラップするようだ。この時、オリジナルのイベントをそのまま継承したり拡張したりはせず、jQuery独自のものになるっぽい。それによる恩恵も大きいので、それはそれでいいのだが、今はDragEvent
が欲しいのだ。
対策
一つは、「jQueryを使わない」という方法。普通に下記のようなコードにすれば、問題なくDragEventを取得できる。
var da = document.getElementById('dragarea');
da.addEventListener('drop', function(e){
if(e.dataTransfer){
console.log("e is DragEvent");
}
});
しかし、他はjQueryでイベント監視してるのに、ここだけバニラというのも美しくない。
もう一つは、jQuery.Event
から取得する方法である。jQuery.Event
は、オリジナルのイベントをラップするのだが、その際、ちゃんとそのオリジナルのイベントを取得する方法が用意されている。それがjQuery.Event.originalEvent
だ。
これを本来の引数であるとして用いれば、問題なくdataTransfer.files
にアクセスすることができた。
$d.on("drop", function(_e){
var e = _e;
if( _e.originalEvent ){
e = _e.originalEvent;
}
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer;
var files = dt.files;
handleFiles(files);
});
参考サイト
- Web アプリケーションからファイルを扱う | MDN https://developer.mozilla.org/ja/docs/Using_files_from_web_applications
- JavaScript でのローカル ファイルの読み込み - HTML5 Rocks http://www.html5rocks.com/ja/tutorials/file/dndfiles/
- html5 - using jquery .on for drop events when uploading files from the desktop? - Stack Overflow http://stackoverflow.com/questions/9544977/using-jquery-on-for-drop-events-when-uploading-files-from-the-desktop