LoginSignup
33
34

More than 5 years have passed since last update.

jQueryでDropイベントを受け取る方法

Posted at

きっかけ

ブラウザからサーバーにファイルをアップロードする際、アップロードするファイルを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

動作について

このページを開き、点線エリアにファイルをドラッグ・アンド・ドロップすると、ejQuery.Eventクラスのインスタンスになっている。ドラッグ・アンド・ドロップされたファイルは、DragEventクラスのインスタンスが持つdataTransfer.filesプロパティから取得するのだが、jQuery.Eventにはこのプロパティが含まれていない。

原因

クラス名を見て分かる通り、jQueryは本来起きるEventjQuery.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);
    });

参考サイト

33
34
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
34