web-dev-qa-db-ja.com

ファイルまたはフォルダーがドロップされる前にドラッグされているかどうかを区別する方法は?

フォルダーまたはファイルがdragoverまたはdragenterイベント。

例えば:

ondropイベントには、MouseEventという名前のフィールドがあり、dataTransferという名前のフィールドがあり、ファイル(.files)またはアイテム(.items)がリストされています)、ブラウザに応じて、 ChromeFirefox の両方で読むことができます。ただし、dragoverおよびdragenterイベントの場合、これらのフィールド(.filesおよび.items)は空です。問題は、ドロップするのではなく、ドラッグするときにその情報が必要なことです

注:ファイルとフォルダーの両方についてevent.dataTransfer.types[i] === "Files"true

背景調査

次の回答 が私の質問に部分的に適合することがわかりました:

WebKit、つまりChromeでは、getDataをいつ呼び出すことができるかについて非常に制限されています。 dragstartまたはdragover内では許可されていません。これは標準的なバグだと思います。

しかし、その答えは2012年からのものであり、トピックに関する実際の更新情報が見つかりません。したがって、これに関する更新情報を探しています。

58

TL; DRできない:(

この質問がまだ受け入れられていない理由を疑問に思っている場合は、read this meta question作成者OP、および 私の答え

HTML5のdrag/dropファイル

このトピックに関する多くのドキュメントでいくつかの調査を行い、さまざまなブラウザーで自分でテストしたので、ここでファイルのドラッグアンドドロップについて知っているすべてを要約することにしました。

ドラッグ

ファイルをドラッグするとき、次のようないくつかのリスナーを使用できます。

  • dragenter
  • dragover
  • dragend
  • dragleave

これらがdragイベントであるとすると、event.dataTransferfilesプロパティはlength == 0を持つか、空(null)になります。

ドラッグイベントでファイルの詳細を読み込めず、フォルダであるかどうかをできません。これはバグではなく、セキュリティ対策です。

ドラッグイベントでファイルを読み取ることができると想像してください。ユーザーがサイトにファイルをアップロードしたくない場合でも、すべてを読み取ることができます。真面目には意味がありません。デスクトップから別のフォルダーにファイルをドラッグしているときに、誤ってそれをWebページにドラッグするとします。Webページがファイルを読み取り、サーバーに個人情報を保存します...thatセキュリティ上の大きな欠陥になります。

ただし、配列event.dataTransfer.typesを反復処理することで、ユーザーがファイルをドラッグしているかどうか(フォルダーによってファイルなので、フォルダーも意味するファイルごと)を検出できます。ドラッグイベントにファイルが含まれているかどうかを確認する関数を作成し、イベントハンドラーで呼び出すことができます。

例:

function containsFiles(event) {
    if (event.dataTransfer.types) {
        for (var i=0; i<event.dataTransfer.types.length; i++) {
            if (event.dataTransfer.types[i] == "Files") {
                return true;
            }
        }
    }

    return false;
}

function handleDragEnter(e) {
    e.preventDefault();
    if (containsFiles(e)) {
        // The drag event contains files
        // Do something
    } else {
        // The drag event doesn't contain files
        // Do something else
    }
}

落とす

ファイルをドロップ<div>(またはドロップゾーンとして使用している要素)にドロップすると、イベントdropのリスナーを使用して、名前、サイズ、タイプと最終変更日。

ファイルがフォルダーかどうかを検出するには、次のようにします。

  1. フォルダーにはタイプがないため、ファイルにtype == ""があるかどうかを確認します。
  2. フォルダーのサイズは常に4096バイトの倍数(4KiB)であるため、ファイルサイズが4096の倍数かどうかを確認します:size%4096 == 0

例:

function handleDrop(e) {
    e.stopPropagation();
    e.preventDefault();

    var files = e.dataTransfer.files;

    for (var i = 0, f; f = files[i]; i++) { // iterate in the files dropped
        if (!f.type && f.size%4096 == 0) {
            // The file is a folder
            // Do something
        } else {
            // The file is not a folder
            // Do something else
        }
    }
}

既知の問題:そのフォルダは実際にはファイルであるため、これが他の種類のファイルと区別する唯一の方法です。この方法では、ファイルがフォルダーであるという絶対的な確実性は得られませんが、拡張子がなく、サイズが0または正確にN x 4096Bのファイルである可能性があります。


実施例

上記で実際に言ったことを確認し、それを自分でテストするための実用的な例をいくつか示します。実行する前に、ブラウザが ドラッグアンドドロップ機能をサポート であることを確認してください。楽しんで:

91
Marco Bonelli

これはDropping -on drop event-で動作します(これはdragoverイベントでは動作しないことに注意してください):

isDraggedItemIsFile = function(e) {
// handle FF
if (e.originalEvent.dataTransfer.files.length == 0) {
    return false;
}
// handle Chrome
if (e.originalEvent.dataTransfer.items) {
    if (typeof (e.originalEvent.dataTransfer.items[0].webkitGetAsEntry) == "function") {
        return e.originalEvent.dataTransfer.items[0].webkitGetAsEntry().isFile;
    } else if (typeof (e.originalEvent.dataTransfer.items[0].getAsEntry) == "function") {
        return e.originalEvent.dataTransfer.items[0].getAsEntry().isFile;
    }
}
return true;
};

$forms.on('drop', function(e) {
        if (isDraggedItemIsFile(e)) {
            // do something if file
        } else{
           // is directory
        }
    });

FF V49でテスト、Chrome V55、Edge V25

0
Anas

draggedであるページの全体のMimetypeを取得できました。 Mimetypeはフォルダでは空白のように見えるので、そのように区別できるかもしれません。

部分的なコード(Reactから抽出):

function handleDragOver(ev: DragEvent) {
    ev.preventDefault();
    ev.dataTransfer!.dropEffect = 'copy';
    console.log(Array.from(ev.dataTransfer.items).map(i => [i.kind,i.type].join('|')).join(', '));
}

document.addEventListener('dragover',handleDragOver);

出力は次のようになります。

file|image/x-icon, file|image/jpeg, file|application/vnd.ms-Excel

ページ上に3つのファイルをドラッグすると。

ローカルホストでのみ動作するかどうかはわかりませんが、まだどこにもアップロードしていませんが、完全に動作しています。

DataTransferItemのMDNドキュメント

0
mpen

FileReaderまたはwebkitGetAsEntry()を使用して、フォルダーからファイルを分離できます。

WebkitGetAsEntry()はie11でサポートされていないため、注意してください!

コードは次のようになります。

 onDrop(event) {
    let files = event.dataTransfer ? event.dataTransfer.files : 'null';

    for(let i = 0, file; file = files[i]; i++) {
       var reader = new FileReader();

       reader.onload = function (e) {
           console.log('it is a file!');
       };
       reader.onerror = function (e) {
          console.log('it is a folder!');
       };

       reader.readAsText(file);
    }

}
0