首页 文章

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

提问于
浏览
132

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

但有时候我们不喜欢拖放文件 - 一次很多 - into a standard HTML file input<input type=file multiple> .

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

Why? 因为我想提交一份正常的表格 . 适用于所有浏览器和所有设备 . 拖放只是渐进式增强,以增强和简化用户体验 . 标准文件输入( multiple 属性)的标准表格将在那里 . 我想添加HTML5增强功能 .

edit
我知道在 some 浏览器中你可以 sometimes (几乎总是)将文件放入文件输入本身 . 我知道Chrome通常会这样做,但有时它会失败然后将文件加载到当前页面中(如果您填写表单,则会失败) . 我想傻瓜和浏览器一样 .

12 回答

  • 2

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

    $(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

    以下适用于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处理程序 - 这只是为了简洁起见 .

  • 3

    对于那些希望在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值 Span 吗?这就是我们打印出文件名的地方 .

    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;
        }
    });
    

    就是这样 .

  • 40

    这是“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?

  • 1
    //----------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>
    
  • 26

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

    除了文件输入是 read-only . 这是一个老问题 .

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

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

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

  • 44

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

    当您将文件放入放置区时,您会得到一个dataTransfer.files对象,它是一个“FileList”类型的对象,它包含您拖动的所有文件 . 同时,element具有属性“files”,即相同的“FileList”类型对象 .

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

  • 6

    对于仅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

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

  • 8

    几年后,我已经构建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();
    
  • 3

    这就是我的结果 .

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

    您可以做的是显示文件输入并将其覆盖在您的透明放置区域,小心使用像 file[1] 这样的名称 . {一定要 enctype="multipart/form-data" 在您的FORM标签内 . }

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

    最后(前端)提交表格 .


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

相关问题