在Google Chrome / Chromium和Safari中拖放文件上传?


68

拖放文件上传可以在Firefox 3.6中完成。

Google搜索html5拖放文件上传-gmail可以得到以下结果:

所有这些指南都使用FileReader(或不推荐使用Firefox 3.6 getAsBinary,也没有其他浏览器支持)。

但是,Google最近发布了Gmail更新,该更新允许在Chromium和Firefox中上传和拖放文件,而Chromium没有FileReader。我每晚都在使用最新的Chromium,它可以拖放上传文件,但不支持FileReader

我见过有人提到,可以通过拖放到上进行拖放上载<input type="file" />,但一次只能支持一个文件,而Gmail的上载器可以处理被拖放到其上的多个文件,因此显然不是它们在做。

所以问题是,他们怎么做到的?您如何支持Chromium上载HTML5文件?另外,您可以支持Safari吗?


2
PS阅读源代码非常困难,因为Gmail的源代码由于对其进行的所有优化而非常混乱。
Zarel

1
PPS FileListHTML的PPS<input type="file" />是只读的,因此您也不能将拖放的文件移植到其中一个文件中。
Zarel

是否可以更改此帖子的标题?我刚刚在“ Chrome”中发布了一个重复的问题,询问“拖放”问题,但这与该问题不匹配,因为标题使用的是Chromium(大多数人不使用)。
克里斯·R

好的,我已经更改标题了。
Zarel 2010年

Answers:


33

警告:这是非常旧版本的Safari和Chrome的兼容性代码。现代的浏览器都支持FileReader API。这是一个教程:https : //developer.mozilla.org/zh-CN/docs/Using_files_from_web_applications

现在,仅在出于某些原因需要支持Safari 5和更高版本或Chrome 6和更高版本的情况下,此代码才有用。


一种可能性是使用SwellJS中使用的方法

<input type="file" multiple="multiple" />像这样使用:

<form method="post" enctype="multipart/form-data" id="uploadform">
  <input type="file" name="dragupload[]" multiple="multiple"
  onchange="if (this.value) document.getElementById('uploadform').submit();" />
</form>

可以设置输入元素的样式,使其具有opacity: 0并(绝对)位于接受上载的元素上。整个表单可以放置在iframe类似“ Ajax”的行为中。并且上载元素可以是隐藏的层,直到在其上拖动某些东西为止。

这样的iframe如下所示:

<script>
<!--
  var entered = 0;
-->
</script>
<body ondragenter="entered++;document.getElementById('uploadelement').style.display='block'" ondragleave="entered--;if (!entered) document.getElementById('uploadelement').style.display='none'">
  <form method="post" enctype="multipart/form-data" id="uploadform">
    Things can be dragged and dropped here!
    <input type="file" id="uploadelement" name="dragupload[]" multiple="multiple" onchange="if (this.value) { document.getElementById('uploadform').submit(); }" style="display:none;position:absolute;top:0;left:0;right:0;bottom:0;opacity:0;" />
  </form>
</body>

仅当检测到Safari或Chrome时才应执行此操作(因为其他浏览器不支持拖放到<input type="file" />元素上),并且可以与dropFirefox 3.6+的HTML5事件结合使用。

我无法确定这是否是Gmail使用的方法,但它当然也可以使用。


显示/隐藏代码上的条目计数增加/减少技巧非常方便。
山姆·巴纳姆

感谢您对这篇文章。您可以从这里链接到完整示例吗?其中一个可能包含服务器端代码?或者只是解释(在asp.net)我如何可以访问这种形式(“uploadForm”)已提交的文件
盖伊

13

您可能对更符合技术和浏览器标准的东西感兴趣。

在我看来,Plupload做得很好,支持以下功能:

  • 块状
  • 拖放
  • PNG调整大小
  • JPEG调整大小
  • 类型过滤
  • 流上传
  • 分段上传
  • 文件大小限制
  • 上传进度

适用于以下大多数技术:

  • 齿轮
  • HTML 5
  • 银光
  • BrowserPlus

是的,自2010.05.27以来,它支持在Chrome Beta上运行的HTML5的拖放。


哦?您是否尝试过此页面的“ HTML 5运行时”?plupload.com/example_all_runtimes.php
Arnaud Leymet 2010年

2
HTML5运行时版本适用于OS X上的6.0.472.25开发人员。它似乎也适用于Firefox 4 beta。
詹姆斯·斯奈德

1
HTML5上载对我也适用于WinXp上的Chrome 8.552.210 Beta(仅几个月,他们已经拥有2个版本)。无论如何,谢谢你的帖子!
IgalSt

对我来说:在html5运行时下,FF 15.0.1可以工作;Chrome 21没有。
蒂姆(Tim)

10

经过大量的侦探工作,我在Chrome中有了一些工作。这适用于Chrome。在Safari上,它冻结。在Firefox上,它不允许我删除文件。IE而是打开删除的文件。即使在Chrome中,由于某种原因,拖放操作也只能工作一次,之后您必须刷新页面。(这样做的可能原因是事件处理程序有问题。)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <script type="text/javascript">
            window.onload = function () {
                var div = document.getElementById('div');
                div.ondragenter = div.ondragover = function (e) {
                    e.preventDefault();
                    e.dataTransfer.dropEffect = 'copy';
                    return false;
                }
                div.ondrop = function (e) {
                    for (var i = 0; i < e.dataTransfer.files.length; i++) { // e.dataTransfer is a DataTransfer object (https://developer.mozilla.org/En/DragDrop/DataTransfer), e.dataTransfer.files is a FileList object (https://developer.mozilla.org/en/DOM/FileList)
                        var file = e.dataTransfer.files[i]; // file is a File object (https://developer.mozilla.org/en/DOM/File)

                        var xhr = new XMLHttpRequest;
                        xhr.open('post', 'handler.php', true);
                        xhr.onreadystatechange = function () {
                            if (this.readyState != 4)
                                return;
                            document.body.innerHTML += '<pre>' + this.responseText + '</pre>';
                        }
                        xhr.setRequestHeader('Content-Type', 'multipart/form-data');
                        xhr.setRequestHeader('X-File-Name', file.fileName);
                        xhr.setRequestHeader('X-File-Size', file.fileSize);
                        xhr.send(file); // For some reason sending the actual File object in Chrome works?
                    }

                    e.preventDefault();
                    return false;
                }
            }
        </script>
    </head>
    <body>
        <div id="div" style="width: 100%; height: 200px; border: 1px solid blue">Drop here</div>
    </body>
</html>

handler.php:

    // This is not a true file upload. Instead, it sends the raw data directly.
    echo htmlentities(file_get_contents('php://input'));

3
使用document.body.innerHTML + =会破坏dom事件。避免这种情况将解决您的问题。
Joseph Montanez 2010年

效果很好,我由gmail开发人员告知,您应该为FF3.6 +使用dropEffect ='move',尚未在FF中进行测试,所以不确定是否仍然需要
gatapia 2011年

2

您无需使用iframe即可进行伪ajax上传。Chrome和Safari都支持带有进度事件的XHR2上传,因此您可以执行进度栏等。


...是的,这很明显。这里的问题是我看过的所有教程都使用XHR2FileReadergetAsBinary()(即Chrome不支持的功能)上传文件。我怀疑这是必需的,所以我在这里基本上要问的是,如果有人想要Chrome支持,应该怎么做。
Zarel '04

2

对于我们自己的应用程序,我们仅拖放FireFox。我们将其恢复为传统的iframe上传。为了检测到支持拖放,我们运行以下代码:

if (typeof(window.File) == 'object' && typeof(window.FileReader) == 'function' && typeof(window.FileList) == 'object') {
   // DnD is supported!
}

希望这对某些人有帮助。


您确实提到只对FireFox进行拖放,但是对于可能使用此代码的其他人window.FileReader,即使Safari 5(Windows)能够很好地处理文件丢失,它也会为检查返回false 。仍在寻找可靠的浏览器功能来检测文件拖放...
Chris


1

最新的浏览器支持文件上传良好。您可以使用:

xhr = new XMLHttpRequest();     
xhr.open('POST', targetPHP, true);
var formData = new FormData();
formData.append('upload',file);
xhr.send(formData);

您无需设置边界或任何头部,就可以像这样正常工作。我在client:firefox 6.02和chrome 13中测试了此代码。server:tomcat与“ spring mvc”


0

您可以使用FormData存储文件,然后上载它。例如

function setUp(){
  var dropContainer = document.getElementById("container");
  dropContainer.addEventListener("drop",dropHandler,false);
  dropContainer.addEventListener("dragenter", function(event){event.stopPropagation();event.preventDefault();}, false);
  dropContainer.addEventListener("dragover", function(event){event.stopPropagation();event.preventDefault();}, false);
  dropContainer.addEventListener("drop", dropHandler, false);
  getResult()
}
function dropHandler(event){
  var files = event.dataTransfer.files;
  var count = files.length;
  form = new FormData();
  for(var i= 0;i<count;i++){
    form.append("file"+i, files[i]);
  }
  sendData();
}
function sendData(){
  var xhr = new XMLHttpRequest();  
  xhr.upload.addEventListener("progress", uploadProgress, false);  
  xhr.addEventListener("load", uploadComplete, false);
  xhr.addEventListener("error", uploadFailed, false);  
  xhr.open("POST", "/upload");
  xhr.send(form);
  var progressBar = document.getElementById('progressBar');
  progressBar.style.display = 'block';
  progressBar.style.width = '0px';
}

演示在这里(http://flexinnerp.appspot.com/)尽情享受吧:)


0

设置多个属性,例如:

输入type =“ file” name =“ file1” multiple =“ multiple” class =“ DropHere”

并使用以下CSS DropHere类:

.DropHere
{
    height: 100px;
    padding: 3px;
    border: 2px dashed #555;
    border-radius: 5px;
    cursor: default;
    background-image:url("data:image/svg+xml;utf8, <svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='100px' width='220px'><text x='55' y='75' font-size='20'>or drop files here</text></svg>");
    background-repeat: no-repeat;
}

文件字段现在看起来像:

该文件现在看起来像

如果您使用asp.net,您可能还会喜欢这篇文章,我写了“使用进度条拖放多个文件”:http : //www.codeproject.com/Articles/818561/Multiple-file-upload-with-progress -并拖动

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.