web-dev-qa-db-ja.com

ドロップファイルを標準のHTMLファイル入力にドラッグします

最近では、ファイルを特別なコンテナーにドラッグアンドドロップし、XHR 2でアップロードできます。ライブプログレスバーなど。非常にクールなもの。 ここの例

しかし、時にはそれほどクールにしたくないことがあります。私がしたいのは、ファイルをドラッグアンドドロップすることです-一度に多く-を標準のHTMLファイル入力に:<input type=file multiple>

それは可能ですか?ファイルドロップから正しいファイル名(?)でファイル入力を「埋める」方法はありますか? (ファイルシステムのセキュリティ上の理由から、完全なファイルパスは使用できません。)

理由?通常のフォームを送信したいので。すべてのブラウザおよびすべてのデバイス用。ドラッグアンドドロップは、UXを強化および簡素化するための単なる進歩的な強化です。標準ファイル入力(+ multiple属性)を持つ標準フォームがそこにあります。 HTML5の拡張機能を追加したいと思います。

編集
私はsomeブラウザでできることを知っていますsometimes(ほとんどの場合、ファイルをファイル入力自体にドロップします。 Chromeが通常これを行うことを知っていますが、時々失敗し、現在のページにファイルをロードします(フォームに入力している場合は大きな失敗です)。私はそれを馬鹿にしたいと思います。

135
Rudie

私はこれに対する解決策を作りました。

$(function () {
    var dropZoneId = "drop-zone";
    var buttonId = "clickHere";
    var mouseOverClass = "mouse-over";

    var dropZone = $("#" + dropZoneId);
    var ooleft = dropZone.offset().left;
    var ooright = dropZone.outerWidth() + ooleft;
    var ootop = dropZone.offset().top;
    var oobottom = dropZone.outerHeight() + ootop;
    var inputFile = dropZone.find("input");
    document.getElementById(dropZoneId).addEventListener("dragover", function (e) {
        e.preventDefault();
        e.stopPropagation();
        dropZone.addClass(mouseOverClass);
        var x = e.pageX;
        var y = e.pageY;

        if (!(x < ooleft || x > ooright || y < ootop || y > oobottom)) {
            inputFile.offset({ top: y - 15, left: x - 100 });
        } else {
            inputFile.offset({ top: -400, left: -400 });
        }

    }, true);

    if (buttonId != "") {
        var clickZone = $("#" + buttonId);

        var oleft = clickZone.offset().left;
        var oright = clickZone.outerWidth() + oleft;
        var otop = clickZone.offset().top;
        var obottom = clickZone.outerHeight() + otop;

        $("#" + buttonId).mousemove(function (e) {
            var x = e.pageX;
            var y = e.pageY;
            if (!(x < oleft || x > oright || y < otop || y > obottom)) {
                inputFile.offset({ top: y - 15, left: x - 160 });
            } else {
                inputFile.offset({ top: -400, left: -400 });
            }
        });
    }

    document.getElementById(dropZoneId).addEventListener("drop", function (e) {
        $("#" + dropZoneId).removeClass(mouseOverClass);
    }, true);

})
#drop-zone {
    /*Sort of important*/
    width: 300px;
    /*Sort of important*/
    height: 200px;
    position:absolute;
    left:50%;
    top:100px;
    margin-left:-150px;
    border: 2px dashed rgba(0,0,0,.3);
    border-radius: 20px;
    font-family: Arial;
    text-align: center;
    position: relative;
    line-height: 180px;
    font-size: 20px;
    color: rgba(0,0,0,.3);
}

    #drop-zone input {
        /*Important*/
        position: absolute;
        /*Important*/
        cursor: pointer;
        left: 0px;
        top: 0px;
        /*Important This is only comment out for demonstration purposes.
        opacity:0; */
    }

    /*Important*/
    #drop-zone.mouse-over {
        border: 2px dashed rgba(0,0,0,.5);
        color: rgba(0,0,0,.5);
    }


/*If you dont want the button*/
#clickHere {
    position: absolute;
    cursor: pointer;
    left: 50%;
    top: 50%;
    margin-left: -50px;
    margin-top: 20px;
    line-height: 26px;
    color: white;
    font-size: 12px;
    width: 100px;
    height: 26px;
    border-radius: 4px;
    background-color: #3b85c3;

}

    #clickHere:hover {
        background-color: #4499DD;

    }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="drop-zone">
    Drop files here...
    <div id="clickHere">
        or click here..
        <input type="file" name="file" id="file" />
    </div>
</div>

このメソッドのドラッグアンドドロップ機能は、Chrome、Firefox、およびSafariでのみ機能します。 (IE10で動作するかどうかはわかりません)が、他のブラウザーの場合、[またはここをクリックしてください]ボタンは正常に機能します。

入力フィールドは、ファイルをある領域にドラッグするときにマウスをたどるだけで、ボタンも追加しました。

不透明度のコメントを解除します:0;ファイル入力は表示されるだけなので、何が起こっているのかを見ることができます。

46
BjarkeCK

以下はChromeおよびFFで動作しますが、IE10 +をカバーするソリューションもまだ見つけていません。

// dragover and dragenter events need to have 'preventDefault' called
// in order for the 'drop' event to register. 
// See: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Drag_operations#droptargets
dropContainer.ondragover = dropContainer.ondragenter = function(evt) {
  evt.preventDefault();
};

dropContainer.ondrop = function(evt) {
  // pretty simple -- but not for IE :(
  fileInput.files = evt.dataTransfer.files;
  evt.preventDefault();
};
<!DOCTYPE html>
<html>
<body>
<div id="dropContainer" style="border:1px solid black;height:100px;">
   Drop Here
</div>
  Should update here:
  <input type="file" id="fileInput" />
</body>
</html>

おそらく、addEventListenerまたはjQuery(など)を使用してevtハンドラーを登録することをお勧めします-これは簡潔にするためです。

45
jlb

これがHTML5の「DTHML」方法です。標準形式の入力(ISは、リカルドトマシが指摘したように読み取り専用)。次に、ファイルをドラッグすると、フォームに添付されます。この方法でアップロードされたファイルを受け入れるには、アクションページを変更する必要があります。

function readfiles(files) {
  for (var i = 0; i < files.length; i++) {
    document.getElementById('fileDragName').value = files[i].name
    document.getElementById('fileDragSize').value = files[i].size
    document.getElementById('fileDragType').value = files[i].type
    reader = new FileReader();
    reader.onload = function(event) {
      document.getElementById('fileDragData').value = event.target.result;}
    reader.readAsDataURL(files[i]);
  }
}
var holder = document.getElementById('holder');
holder.ondragover = function () { this.className = 'hover'; return false; };
holder.ondragend = function () { this.className = ''; return false; };
holder.ondrop = function (e) {
  this.className = '';
  e.preventDefault();
  readfiles(e.dataTransfer.files);
}
#holder.hover { border: 10px dashed #0c0 !important; }
<form method="post" action="http://example.com/">
  <input type="file"><input id="fileDragName"><input id="fileDragSize"><input id="fileDragType"><input id="fileDragData">
  <div id="holder" style="width:200px; height:200px; border: 10px dashed #ccc"></div>
</form>

ウィンドウ全体をドロップゾーンにすることができればさらに上司です。 Gmailのようにウィンドウに出入りするHTML5ドラッグイベントを検出するにはどうすればよいですか?

26
//----------App.js---------------------//
$(document).ready(function() {
    var holder = document.getElementById('holder');
    holder.ondragover = function () { this.className = 'hover'; return false; };
    holder.ondrop = function (e) {
      this.className = 'hidden';
      e.preventDefault();
      var file = e.dataTransfer.files[0];
      var reader = new FileReader();
      reader.onload = function (event) {
          document.getElementById('image_droped').className='visible'
          $('#image_droped').attr('src', event.target.result);
      }
      reader.readAsDataURL(file);
    };
});
.holder_default {
    width:500px; 
    height:180px; 
    border: 10px dashed #ccc;
}

#holder.hover { 
    width:400px; 
    height:180px; 
    border: 10px dashed #0c0 !important; 
}

.hidden {
    visibility: hidden;
}

.visible {
    visibility: visible;
}
<!DOCTYPE html>

<html>
    <head>
        <title> HTML 5 </title>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.js"></script>
    </head>
    <body>
      <form method="post" action="http://example.com/">
        <div id="holder" style="" id="holder" class="holder_default">
          <img src="" id="image_droped" width="500" height="180" style="width:500px; height:180px; border: 10px dashed #7A97FC;" class=" hidden"/>
        </div>
      </form>
    </body>
</html>
8
Dipak

理論的には、<input/>にオーバーレイする要素を追加し、そのdropイベントを使用してファイルをキャプチャし(File APIを使用)、入力files配列に渡します。

ファイル入力が読み取り専用であることを除きます。これは古い問題です。

ただし、フォームコントロールを完全にバイパスし、XHRを介してアップロードすることはできます(そのサポートについてはわかりません)。

また、周囲の領域の要素を使用して、Chromeのドロップイベントをキャンセルし、ファイルをロードするデフォルトの動作を防ぐこともできます。

入力に複数のファイルをドロップすると、SafariとFirefoxですでに機能します。

6
Ricardo Tomasi

私はChromeでいくつかのトリックが機能することを知っています:

ファイルをドロップゾーンにドロップすると、dataTransfer.filesオブジェクト、つまりFileListタイプのオブジェクトが取得され、ドラッグしたすべてのファイルが含まれます。一方、<input type="file" />要素にはプロパティfilesがあり、これは同じFileList型オブジェクトです。

そのため、単にdataTransfer.filesオブジェクトをinput.filesプロパティに割り当てることができます。

4
Timur Gilauri

CSSのみのソリューションの場合:

<div class="file-area">
    <input type="file">
    <div class="file-dummy">
        <span class="default">Click to select a file, or drag it here</span>
        <span class="success">Great, your file is selected</span>
    </div>
</div>

.file-area {
    width: 100%;
    position: relative;
    font-size: 18px;
}
.file-area input[type=file] {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    opacity: 0;
    cursor: pointer;
}
.file-area .file-dummy {
    width: 100%;
    padding: 50px 30px;
    border: 2px dashed #ccc;
    background-color: #fff;
    text-align: center;
    transition: background 0.3s ease-in-out;
}
.file-area .file-dummy .success {
    display: none;
}
.file-area:hover .file-dummy {
    border: 2px dashed #1abc9c;
}
.file-area input[type=file]:valid + .file-dummy {
    border-color: #1abc9c;
}
.file-area input[type=file]:valid + .file-dummy .success {
    display: inline-block;
}
.file-area input[type=file]:valid + .file-dummy .default {
    display: none;
}

https://codepen.io/Scribblerockerz/pen/qdWzJwから変更

3
Jonathan

2018年にこれを行うことを考えている人にとっては、ここに投稿されたすべての古いものよりもはるかに優れたシンプルなソリューションがあります。 Vanilla HTML、JavaScript、CSSだけで見栄えの良いドラッグアンドドロップボックスを作成できます。

(これまではChromeでのみ動作します)

HTMLから始めましょう。

<div>
<input type="file" name="file" id="file" class="file">
<span id="value"></span>
</div>

次に、スタイリングに進みます。

    .file {
        width: 400px;
        height: 50px;
        background: #171717;
        padding: 4px;
        border: 1px dashed #333;
        position: relative;
        cursor: pointer;
    }

    .file::before {
        content: '';
        position: absolute;
        background: #171717;
        font-size: 20px;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 100%;
        height: 100%;
    }

    .file::after {
        content: 'Drag & Drop';
        position: absolute;
        color: #808080;
        font-size: 20px;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

これを実行した後、すでに問題なく見えます。しかし、実際にアップロードしたファイルを確認したいと思うので、JavaScriptを実行します。そのpfp値のスパンを覚えていますか?ここで、ファイル名を出力します。

let file = document.getElementById('file');
file.addEventListener('change', function() {
    if(file && file.value) {
        let val = file.files[0].name;
        document.getElementById('value').innerHTML = "Selected" + val;
    }
});

以上です。

2
Michael

@BjarkeCKによる素晴らしい仕事。 jqueryのメソッドとして使用するために、彼の作品にいくつかの変更を加えました。

$.fn.dropZone = function() {
  var buttonId = "clickHere";
  var mouseOverClass = "mouse-over";

  var dropZone = this[0];
  var $dropZone = $(dropZone);
  var ooleft = $dropZone.offset().left;
  var ooright = $dropZone.outerWidth() + ooleft;
  var ootop = $dropZone.offset().top;
  var oobottom = $dropZone.outerHeight() + ootop;
  var inputFile = $dropZone.find("input[type='file']");
  dropZone.addEventListener("dragleave", function() {
    this.classList.remove(mouseOverClass);
  });
  dropZone.addEventListener("dragover", function(e) {
    console.dir(e);
    e.preventDefault();
    e.stopPropagation();
    this.classList.add(mouseOverClass);
    var x = e.pageX;
    var y = e.pageY;

    if (!(x < ooleft || x > ooright || y < ootop || y > oobottom)) {
      inputFile.offset({
        top: y - 15,
        left: x - 100
      });
    } else {
      inputFile.offset({
        top: -400,
        left: -400
      });
    }

  }, true);
  dropZone.addEventListener("drop", function(e) {
    this.classList.remove(mouseOverClass);
  }, true);
}

$('#drop-zone').dropZone();

作業フィドル

1
Mr_Green

数年後、私は this library を構築して、HTML要素にファイルをドロップしました。

次のように使用できます

const Droppable = require('droppable');

const droppable = new Droppable({
    element: document.querySelector('#my-droppable-element')
})

droppable.onFilesDropped((files) => {
    console.log('Files were dropped:', files);
});

// Clean up when you're done!
droppable.destroy();
1
Joel Hernandez

これは私が出てきたものです。

JqueryとHtmlを使用します。これにより、挿入ファイルに追加されます。

var dropzone = $('#dropzone')


dropzone.on('drag dragstart dragend dragover dragenter dragleave drop', function(e) {
    e.preventDefault();
    e.stopPropagation();
  })

dropzone.on('dragover dragenter', function() {
    $(this).addClass('is-dragover');
  })
dropzone.on('dragleave dragend drop', function() {
    $(this).removeClass('is-dragover');
  })  
  
dropzone.on('drop',function(e) {
        var files = e.originalEvent.dataTransfer.files;
        // Now select your file upload field 
        // $('input_field_file').prop('files',files)
  });
input {       margin: 15px 10px !important;}

.dropzone {
        padding: 50px;
        border: 2px dashed #060;
}

.dropzone.is-dragover {
  background-color: #e6ecef;
}

.dragover {
        bg-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div class="" draggable='true' style='padding: 20px'>
        <div id='dropzone' class='dropzone'>
                Drop Your File Here
        </div>
        </div>
0
Lionel Yeo