拖拽并自动上传至服务器(译)

我发现有很多演示和教程都告诉你怎样把一个文件拖放至浏览然后提交页面,这些常常被叫做是“拖放上传”,但实际上他们根本没有上传。这个过程其实还有一步没走完。

我会给你演示这个例子,文件拖到一个网页,然后该文件瞬间成功上传服务器,你也可以试试。

任务列表:该任务由以下几个详尽的步骤

  1. 抓取拖放事件,阅读它的资料。
  2. 发送二进制数据至服务器。
  3. 提交过程中提供反馈。
  4. 随意预览正在上传的文件和当时的状态

我们需要以下HTML5和非HTML5的接口来完成上面步骤:

  1. 拖放
  2. 表单数据
  3. XHR进程
  4. 文件读取器

记住不是所有的浏览器都支持现在这些步骤的API的,但是他们的兼容越来越好了。我想写出一个清晰的教程让大家从头至尾完成这个试验。

结论:可以拖动文件到浏览器的任何部位,知道它的上传情况,这些都不是费力的事。

拖放演示页面

拖拽并自动上传至服务器(译)

拖放文件并传输到数据库的实例页面截图

拖放

正如之前提示,目前拖放被大家认为是有点煞风景的。实际上,它还是个噩梦,不过我这里就不重复之前说过的了。

之前我们的例子教大家如何在浏览器里使用拖放上传文件,为了实现它,我们还需要在body或者 documentElement (i.e., the root HTML node)上装一个事件监听器。通过监听,这个代码可能会出现在页面的任何位置,documentElement一直存在。而且只有当元素出现的时候你才能监听body。

下面是一个整个文件中我们需要抓取拖放事件的代码模式:

var doc = document.documentElement;
doc.ondragover = function () { this.className = 'hover';return false; };
doc.ondragend = function () { this.className = ''; returnfalse; };
doc.ondrop = function (event) {
event.preventDefault && event.preventDefault();
this.className = '';

// now do something with:
var files = event.dataTransfer.files;

return false;
};

抓取拖放事件基本模式

在类上悬停然后我可以切换出一个提示告诉用户这个文件可以被拖放至页面。

在拖放事件里边,我们可以通过event.dataTransfer.files. 使用拖放。

拖放之间的选择

有点悲剧的是,当我写这些的时候,我发现目前只有谷歌和火狐的浏览器允许那些接口同时兼容。所以通过Modernizr我们来试验其兼容性,提出我们的方法。

var dndSupported = function () {
    var div = document.createElement('div');
    return ('draggable' in div) || ('ondragstart' in div &&'ondrop' in div);
};

if (!dndSupported()) {
    // take alternative route
}
拖放兼容试验

我们还可以插入一个输入元素文件(我之前给它定义为”upload”)当它发生改变时,这个文件就可以被上载。

document.getElementById('upload').onchange = function (event){
    // `this` refers to the element the event fired upon
    var files = this.files;
};
本地拖放的一种方法

你可以看到,这个和HTMLInputElement 对象中的文件属性是等价的。它能使我们通过drop事件以event.dataTransfer.files的形式访问相同的文件。

自动上载文件

这是一个规整的二进位制比特,它相当简单。我们要利用到XHR2 spec的特性FormData。一旦创建了FormData实例,就可以往里边添加项目:

var formData = new FormData();
    for (var i = 0; i < files.length; i++) {
    formData.append('file', files[i]);
    }
    // now post a new XHR request
        var xhr = new XMLHttpRequest();
        xhr.open('POST', '/upload');
        xhr.onload = function () {
        if (xhr.status === 200) {
        console.log('all done: ' + xhr.status);
    } else {
        console.log('Something went terribly wrong...');
    }
};
xhr.send(formData);
创建和发布FormData

对,就是这样。

让我们来看下上边代码中这几个关键,formData.append('file', files[i]);

我们向服务器发送命名参数,尤其是一组阵列值被称为“file”的东西。当然,你可以叫他任何名字,但是当他被保存至上载文件的时候,服务器就只认定这个事件设定好的名字了。

xhr.onload = function () {
    if (xhr.status === 200) {
    console.log('all done: ' + xhr.status);
} else {
    console.log('Something went terribly wrong...');
}
};

如果你对XHR很熟悉,你会注意到你不是在监听readystatechange,而是load。它让你知道就绪状态显示4(i.e.下载),非常方便。为了确保它200 ok,你仍然需要适当地检查和响应请求代码状态。注意500(内部服务器错误),404(没被找到)或者其他的都不行。

xhr.send(formData);

这有个不错的小窍门,XHR可以在multipart/form-data自动设置发出来的数据编码,用于服务器读取和保存文件。这样操作起来类似发送邮件时添加附件。

向用户反馈

XHR2(flippin' finally) 现在有了新的突破。比如通过XHR发送或者检索一个超大文件,用户可以知道你所在位置距离他们多远。

这非常简单,如果你想跟踪XHR的请求进程,只要收听progress。有个难题曾经困扰了我一段时间,我需要跟踪上载进程,而不是下载。准确的做法是,在XHR upload 里边收听进程:

xhr.upload.onprogress = function (event) {
    if (event.lengthComputable) {
        var complete = (event.loaded / event.total * 100 | 0);
        progress.value = progress.innerHTML = complete;
    }
};

    xhr.onload = function () {
        // just in case we get stuck around 99%
        progress.value = progress.innerHTML = 100;
    };
XHR2’s提交回馈

注意除了 xhr.onprogress, 我们还使用xhr.upload.onprogess。当这个事件被开始,该项事件就支持计算数据量的上载(lengthComputable 部分),然后完成计算。

HTML,我使用 <progress>元素(类似<meter> 的元素,用更恰当的语义表达就是如我们展示任务进程)来告诉用户他们的文件被上载了多少。

<progress id="progress" min="0" max="100"
value="0">0</progress>

注意大多数浏览器上我都使用innerHTML ,他们不支持<progress>。然后某些CSS-功能的产生,innerHTML 和 value 两者的进程都能被支持(可能是比较乐观的说法, 但是那时我对自己还是相当自豪)。

最后,预览

可能是一个不错的补充,我们会给用户一个预览,告诉他们我们为你们在上载什么。这需要 File 接口,尤其是 FileReader 接口。

因为拖放操作(或者 input[type=file])包含了一个文件对象,可以在 FileReader里结束并且获取文件内容。如果是图像之类的,你可以用Base64 数据给用户一个预览。如果是文本,可以用<div>提交。文件的 MIME 形式是可用的因为于文件对象这是其基本属性。

或者让我们来假设它只支持图片。下边是当文件被浏览器接受后运行的预览部分:

var acceptedTypes = {
    'image/png': true,
    'image/jpeg': true,
    'image/gif': true
};

if (acceptedTypes[file.type] === true) {
    var reader = new FileReader();
        reader.onload = function (event) {
            var image = new Image();
            image.src = event.target.result;
            image.width = 100; // a fake resize
            document.body.appendChild(image);
        };
    reader.readAsDataURL(file);
}
提交图像上载预览

我们创建了 FileReader用来读取文件。在上边这个例子,我还使用了 readAsDataURL,当然你还可以用普通文本模式和二进制模式 (按照规范)。
当检测文件和数据是可用的,它会出发load时间,我们的新图片就开始依次创建了。

结语

这个例子可能有点牵强,但是是我为了这个题目特别写的。我已经用过各种技术,对互联网来说这些都相当普遍。实际上那是因为在上载至实际服务器找到一个明确的来源实在有些困难(当然,除了2010下半年为这个题目我自己写的 this example

希望这些小技巧可以组合在一个写出一个应用来,或者发现某些地方还可以应用到的。记住一定要试验这些功能,提交你的用户体验,请负责人地开发。
最后这还有个拖放并自动上传至服务器 ,去试试吧。

翻译自Drag and Drop and Automatically Send to the Server

第一次翻译,翻译的不好,如有疑问可以留言或者去原文观看。

本文源链接:http://www.html5jscss.com/drag-and-drop-to-server.html

转载请注明《拖拽并自动上传至服务器(译)》| html5jscss

评论关闭了.