将文件拖放到标准的html文件输入中

时间:2011-11-04 08:42:14

标签: html5 file-upload drag-and-drop

这些天我们可以拖延将文件拖放到一个特殊容器中并使用XHR 2上传它们。有现场进度条等非常酷的东西。 Example here.

但有时我们不希望那么冷静。我想要的是拖延删除文件 - 一次多个 - 到标准HTML文件输入<input type=file multiple>

这可能吗?有没有办法用文件丢弃中的正确文件名(?)“填充”文件输入? (出于文件系统安全原因,完整文件路径不可用。)

为什么?因为我想提交一份普通表格。适用于所有浏览器和所有设备。拖曳与drop只是渐进式增强,以增强&amp;简化用户体验标准文件输入(+ multiple属性)的标准表格将在那里。我想添加HTML5增强功能。

修改
我知道在某些浏览器中,您可以有时(几乎总是)将文件放入文件输入本身。我知道Chrome通常会这样做,但有时会失败然后将文件加载到当前页面中(如果您填写表单,则会失败)。我想傻瓜 - &amp;浏览器它。

13 个答案:

答案 0 :(得分:46)

我为此做了一个解决方案。

$(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;文件输入仅可见,因此您可以看到正在发生的事情。

答案 1 :(得分:26)

这是“DTHML”HTML5的方式。正常形式输入(仅作为Ricardo Tomasi指出的读取)。然后,如果拖入文件,它将附加到表单。这将需要修改操作页面以接受以这种方式上传的文件。

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>

如果你可以让整个窗口成为放置区,那就更加老板了,请参阅How do I detect a HTML5 drag event entering and leaving the window, like Gmail does?

答案 2 :(得分:8)

//----------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>

答案 3 :(得分:6)

理论上,您可以添加覆盖<input/>的元素,然后使用它的drop事件来捕获文件(使用File API)并将它们传递给输入files数组

文件输入只读除外。这是一个老问题。

但是,您可以完全绕过表单控件并通过XHR上传(不确定是否支持):

您还可以使用周围区域中的元素取消Chrome中的放置事件,并阻止加载文件的默认行为。

在输入上删除多个文件已经可以在Safari和Firefox中使用。

答案 4 :(得分:4)

我知道Chrome中有一些技巧可行。

当您将文件放入放置区时,您会得到一个dataTransfer.files对象,即&#34; FileList&#34;对象类型,包含您拖动的所有文件。同时,元素具有属性&#34;文件&#34;,这是相同的&#34; FileList&#34;类型对象。

因此,您可以简单地将dataTransfer.files对象分配给input.files属性。

答案 5 :(得分:3)

仅限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

答案 6 :(得分:3)

简单易行。您不需要创建新的 FormData 或执行 Ajax 来发送图像。您可以将拖动的文件放入输入字段。

$dropzone.ondrop = function (e) {
    e.preventDefault();
    input.files = e.dataTransfer.files;
}

var $dropzone = document.querySelector('.dropzone');
var input = document.getElementById('file-upload');

$dropzone.ondragover = function (e) { 
  e.preventDefault(); 
  this.classList.add('dragover');
};
$dropzone.ondragleave = function (e) { 
    e.preventDefault();
    this.classList.remove('dragover');
};
$dropzone.ondrop = function (e) {
    e.preventDefault();
    this.classList.remove('dragover');
    input.files = e.dataTransfer.files;
}
.dropzone {
  padding: 10px;
  border: 1px dashed black;
}
.dropzone.dragover {
  background-color: rgba(0, 0, 0, .3);
}
<div class="dropzone">Drop here</div>
<input type="file" id="file-upload" style="display:none;">

答案 7 :(得分:2)

对于所有希望在2018年做到这一点的人,我拥有比这里发布的所有旧东西更好,更简单的解决方案。您可以仅使用普通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;
    }
});

就是这样。

答案 8 :(得分:1)

@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();

<强> Working Fiddle

答案 9 :(得分:1)

几年后,我构建了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();

答案 10 :(得分:0)

这就是我的想法。

使用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>

答案 11 :(得分:0)

这是William Entriken在此给出的示例的改进,错误修复和修改。有一些问题。例如,<input type="file" />中的普通按钮没有执行任何操作(以防用户想要以这种方式上传文件)。

注意:我正在制作一个仅由我使用的Web应用程序,因此仅针对Firefox进行了测试(并改进)。我相信即使您针对跨浏览器的情况进行开发,该代码也很有价值。

function readFile(e) {
  var files;
  if (e.target.files) {
    files=e.target.files
  } else {
    files=e.dataTransfer.files
  }
  if (files.length==0) {
    alert('What you dropped is not a file.');
    return;
  }
  var file=files[0];
  document.getElementById('fileDragName').value = file.name
  document.getElementById('fileDragSize').value = file.size
  document.getElementById('fileDragType').value = file.type
  reader = new FileReader();
  reader.onload = function(e) {
    document.getElementById('fileDragData').value = e.target.result;
  }
  reader.readAsDataURL(file);
}
function getTheFile(e) {
  e.target.style.borderColor='#ccc';
  readFile(e);
}
<input type="file" onchange="readFile(event)">
<input id="fileDragName">
<input id="fileDragSize">
<input id="fileDragType">
<input id="fileDragData">
<div style="width:200px; height:200px; border: 10px dashed #ccc"
     ondragover="this.style.borderColor='#0c0';return false;"       
     ondragleave="this.style.borderColor='#ccc'"       
     ondrop="getTheFile(event); return false;"       
></div>

答案 12 :(得分:-1)

您可以做的是显示文件输入并将其覆盖在您的透明放置区域,小心使用file[1]之类的名称。 {确保您的FORM标记内有enctype="multipart/form-data"。}

然后让drop-area通过为文件2..number_of_files动态创建更多文件输入来处理额外文件,请确保使用相同的基本名称,正确填充value-attribute。

最后(前端)提交表格。


处理此方法所需的只是更改处理文件数组的过程。