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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8006715/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 11:23:04  来源:igfitidea点击:

drag drop files into standard html file input

htmlfile-uploaddrag-and-drop

提问by Rudie

These days we can drag & drop files into a special container and upload them with XHR 2. Many at a time. With live progress bars etc. Very cool stuff. Example here.

现在我们可以将文件拖放到一个特殊的容器中,然后使用 XHR 2 上传它们。一次很多。带有实时进度条等。非常酷的东西。例子在这里。

But sometimes we don't want that much coolness. What I'd like is to drag & drop files -- many at a time -- into a standard HTML file input: <input type=file multiple>.

但有时我们不想那么酷。我想是拖放文件-许多在同一时间-到一个标准的HTML文件输入<input type=file multiple>

Is that possible? Is there some way to 'fill' the file input with the right filenames (?) from the file drop? (Full filepaths aren't available for file system security reasons.)

那可能吗?有什么方法可以从文件放置中用正确的文件名(?)“填充”文件输入?(出于文件系统安全原因,完整的文件路径不可用。)

Why?Because I'd like to submit a normal form. For all browsers and all devices. The drag & drop is just progressive enhancement to enhance & simplify UX. The standard form with standard file input (+ multipleattribute) will be there. I'd like to add the HTML5 enhancement.

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

edit
I know in somebrowsers you can sometimes(almost always) drop files into the file input itself. I know Chrome usually does this, but sometimes it fails and then loads the file in the current page (a big fail if you're filling out a form). I want to fool- & browserproof it.

编辑
我知道在某些浏览器中,您有时(几乎总是)可以将文件放入文件输入本身。我知道 Chrome 通常会这样做,但有时它会失败,然后在当前页面中加载文件(如果您正在填写表单,这是一个很大的失败)。我想愚弄和浏览器保护它。

采纳答案by jlb

The following works in Chrome and FF, but i've yet to find a solution that covers IE10+ as well:

以下适用于 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;

  // If you want to use some of the dropped files
  const dT = new DataTransfer();
  dT.items.add(evt.dataTransfer.files[0]);
  dT.items.add(evt.dataTransfer.files[3]);
  fileInput.files = dT.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>

You'll probably want to use addEventListeneror jQuery (etc.) to register your evt handlers - this is just for brevity's sake.

您可能想要使用addEventListener或 jQuery(等)来注册您的 evt 处理程序 - 这只是为了简洁起见。

回答by BjarkeCK

I made a solution for this.

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

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

The Drag and Drop functionality for this method only works with Chrome, Firefox and Safari. (Don't know if it works with IE10), but for other browsers, the "Or click here" button works fine.

此方法的拖放功能仅适用于 Chrome、Firefox 和 Safari。(不知道它是否适用于 IE10),但对于其他浏览器,“或单击此处”按钮工作正常。

The input field simply follow your mouse when dragging a file over an area, and I've added a button as well..

在一个区域上拖动文件时,输入字段只需跟随您的鼠标,我还添加了一个按钮..

Uncomment opacity:0; the file input is only visible so you can see what's going on.

取消不透明度:0; 文件输入仅可见,因此您可以看到发生了什么。

回答by William Entriken

This is the "DTHML" HTML5 way to do it. Normal form input (which IS read only as Ricardo Tomasi pointed out). Then if a file is dragged in, it is attached to the form. This WILL require modification to the action page to accept the file uploaded this way.

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

It is even more boss if you can make the whole window a drop zone, see How do I detect a HTML5 drag event entering and leaving the window, like Gmail does?

如果您可以使整个窗口成为拖放区,那就更重要了,请参阅如何像 Gmail 一样检测进入和离开窗口的 HTML5 拖动事件?

回答by Dipak

//----------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:150px; 
    border: 3px dashed #ccc;
}

#holder.hover { 
    width:400px; 
    height:150px; 
    border: 3px 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="200" style="border: 3px dashed #7A97FC;" class=" hidden"/>
        </div>
      </form>
    </body>
</html>

回答by Ricardo Tomasi

In theory, you could add an element overlaying the <input/>, and then use it's dropevent to capture the files (using the File API) and pass them to input filesarray.

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

Except that a file input is read-only. This is an old problem.

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

You can however, bypass the form control completely and upload via XHR (not sure about the support for that):

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

You could also use an element in the surrounding area to cancel the drop event in Chrome, and prevent the default behaviour of loading the file.

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

Dropping multiple files over the input already works in Safari and Firefox.

在 Safari 和 Firefox 中已经可以在输入上放置多个文件。

回答by Timur Gilauri

I know some trick works in Chrome:

我知道一些技巧在 Chrome 中有效:

When dropping files into drop zone you get a dataTransfer.filesobject, that is a FileListtype of object, that contains all the files you dragged. Meanwhile, <input type="file" />element has the property files, that is the same FileListtype object.

将文件拖放到拖放区时,您会得到一个dataTransfer.files对象,它是一种FileList对象,其中包含您拖动的所有文件。同时,<input type="file" />元素具有属性files,即同FileList类型对象。

So, you can simply assign the dataTransfer.filesobject to the input.filesproperty.

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

回答by Jonathan

For a CSS only solution:

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

Modified from https://codepen.io/Scribblerockerz/pen/qdWzJw

修改自https://codepen.io/Scribblerockerz/pen/qdWzJw

回答by Lionel Yeo

This is what I came out with.

这是我出来的。

Using Jquery and Html. This will add it to the insert files.

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

回答by Michael

For anyone who's looking to do this in 2018, I've got a much better and simpler solution then all the old stuff posted here. You can make a nice looking drag & drop box with just vanilla HTML, JavaScript and CSS.

对于任何希望在 2018 年做到这一点的人,我有一个更好、更简单的解决方案,而不是这里发布的所有旧东西。你可以只用普通的 HTML、JavaScript 和 CSS 制作一个漂亮的拖放框。

(Only works in Chrome so far)

(目前仅适用于 Chrome)

Let's start with the HTML.

让我们从 HTML 开始。

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

Then we'll get to the styling.

然后我们将进入造型。

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

After you've done this it already looks fine. But I imagine you'd like to see what file you actaully uploaded, so we're going to do some JavaScript. Remember that pfp-value span? That's where we'll print out the file name.

完成此操作后,它看起来已经很好了。但我想你想看看你实际上传了什么文件,所以我们要做一些 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;
    }
});

And that's it.

就是这样。

回答by Joel Hernandez

Few years later, I've built this libraryto do drop files into any HTML element.

几年后,我构建了这个库来将文件放入任何 HTML 元素。

You can use it like

你可以像这样使用它

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