女子小学生と××したい

Webフロントエンド界のゴミクソメンヘラであり続けたい

Drag and Drop APIのモダンブラウザ間の差異に関する考察

お久しぶりです、わたしです。
今日はHTML5(死語)のDrag and Drop APIのモダンブラウザ間にある(と予想される)実装差異についてです。
Drag and Drop API自体につきましてはググってください。
要はDOMを掴んで投げて落として、データの受け渡しとかイベント処理をよしなにできるAPIです、多分。
まぁざっくりとこの記事の要旨を書きますと

webkit系ブラウザは、img要素を入れ子した親要素をdragしようとした際に、dragstartイベントのdataTransfer.setDragImageメソッドが正しく機能しない?
mozilla(Firefox)は、img要素ないしimg要素を内包した親要素でない場合、dragStartイベントのdataTransfer.setDataをしない限りはdragすることができない?

今回、この検証のために書いたコードが以下になります

onload = function(){
    var $elmDrag = $('.drag');
    var $elmDrop = $('.drop');
    var feedbackImg = new Image();
    
    feedbackImg.src = 'http://cdn1.www.st-hatena.com/users/c6/c67n9v6l9/profile.gif';
    
    $elmDrag.on('dragstart',function(e){
        e.originalEvent.dataTransfer.setData('text/plain','hoge');
        e.originalEvent.dataTransfer.setDragImage(feedbackImg,32,32);
    });
    
    $elmDrop.on('dragover',function(e){e.preventDefault()});
    
    $elmDrop.on('drop',function(e){
        e.preventDefault();
        alert('drop');
    });
};

3種類のDOM(imgを内包したdiv、img、div)をdraggableにし、dragstartイベントのリスナー内で、ドラッグ時のフィードバック画像を設定できるdataTransfer.setDragImageで別の画像を設定しています。
右下に設置したdivにdropイベントリスナを貼り、alertを出すという、至極シンプルなものになっています。

で、これをchromesafariFirefoxの3ブラウザでテストしてみました。

あ、先に申しますと、僕みたいな適当な人間によるコードとテストなので、「違うよなんか、それは違うよかるね君!」って人は後ろから殴ってください。

結果なんですが、

chrome,safari -> imgを内包したdivをdragする際、dataTransfer.setDragImageが機能しない
firefox -> divをdragできない

となりました。

と、ここで疑問が1つ

ネイティブ HTML5 ドラッグ&ドロップ - HTML5 Rocks

このページのサンプル、divにも関わらずFirefoxで動作しているんです
はて、僕が書いたコードと何が違うんだろうと根掘り葉掘り調べてみたところ、dragstartイベント時にdataTransfer.setDataを実行しているか否かでした。

細かい実装上の仕様については調べて追記しますが、そういうことのようです。
現に、上記コードでdataTransfer.setDataの行をコメントアウトすると、Firefoxで動作しなくなります。

まとめると

webkit系ブラウザは、img要素を内包する親要素をdragしようとすると、dragstartイベントのdataTransfer.setDragImageが動作しない
firefoxは、img要素でない、若しくはimg要素を内包しない要素をdragする際、dragstartイベントのハンドラでdataTransfer.setDataを実行しないとdragができない

ということになります。
もし違うという指摘がある場合はそっと声をかけてください(弱気)。