我意识到(当看我自己)有很多演示和教程,告诉你如何拖放一个文件到浏览器,然后在页面上呈现。 它们经常被贴上"拖放和上传"的标签,但实际上它们不会上传。 本教程将带您最后一步。
我将引导您浏览一个可以玩的示例:将文件拖动到网页中,该文件将立即上传到服务器。
任务#
让我们将此过程分解为特定任务:
- 捕获放置事件并读取其数据。
- 将该二进制数据过帐到服务器。
- 提供有关上传进度的反馈。
- 可选地呈现正在上载的内容及其状态的预览。
为了实现所有这些,我们需要以下 HTML5 和非 HTML5 API:
请记住,并非所有浏览器都支持所有这些技术,但它们正在接近。 我只是想创建一个清晰和完整的教程,如何去整个猪和上传丢弃的文件。
最终结果是:我们能够将文件投到浏览器的任意位置,我们获得上传的预览和进度,这是一个流畅的体验。

拖放#
正如一个预警,拖放已被称为有点杀人。 事实上,这是一场噩梦,但我不会重复之前说过的。
我们的示例将允许您在浏览器中的任意位置拖放文件。 为此,我们需要将事件侦听器附加到正文或
文档
元
素(即根
HTML 节点)。 通过侦听文档
元素,此代
码可能存在于页面中的任意位置,
因为文档元
素将始终存在。 你只能听身体一
次
<bod
y>
元素。</body>
下面是捕获整个文档中的放置事件所需的代码模式:
var 文档 = 文档. 文档元素;doc. ondragover = 函数 () = 这个. 类名 = "悬停"; 返回 false; =;doc. ondragend = 函数 () = 此. 类名 = ';返回法尔; =;文档. ondrop = 函数 (事件) = 事件. 防止防御 = 事件. 防止防御 (); 这个. 类名称 = ';' 现在对: var 文件 = 事件. datatrans. 文件进行操作; 返回虚假;};
我使用
的是
悬停类,以便可以切换提示,向用户解释文件可以放在页面上。
在删除事件
内,我
们可以通过event.dataTransfer
.files访问丢弃的文件
。
拖放的替代方法#
令人讨厌的是,当我写这篇文章时,我意识到这种API要求的组合目前只满足Chrome和Firefox的要求。 因此,通过 Modernizr 的测试,我们可以测试支持并提供我们的替代方案:
var dnd 支持 = 函数 () = var div = 文档. createElement ('div'); 返回 (在 div 中的 "可拖动" ||(div 中的 "ondragstart";};如果 (: dnd 支持()) = // 采取替代路线 =
我们可以插入文件输入元素(我已赋予它一个"上传"的 I
D),而不是拖放,当文件的值更改时,可以挖掘该文件:
文档. getElementbyId ("上传") . onchange = 函数 (事件) / / "此" 是指事件触发在 var 文件上的元素 = 此. files; =;
您可以看到等效项只是HTMLIn
pu
tEleme
nt对象的文
件属性。 这将允许我们访问与事件相同的文件.da
taTransfer
.文件从放置事件。
自动上传文件#
这是整洁的位, 这是痛苦的简单。 我们使用 XHR2 规范的功能:For
mData
。 创建 FormDat
a
实例后,可以追加项:
var formData = 新的 FormData ();用于 (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.append('文件',文件[i]);
我们将命名参数发送到我们的服务器,特别是称为文件的值数
组
。 显然,您可以调用它所需的,但
该
文件是服务器在保存上传的文件(或文件)时要查找的名称。
xhr. onload = 函数 () = 如果 (xhr. 状态 = 200) = 控制台.log ("全部完成:" = xhr. 状态); [否则] 控制台.log ('出了大错事...'); } };
如果您熟悉 XHR,您会注意到我们不是在侦听 toon
readstat
ech
ang
e,只是在加载上, 这是一个方便功能,让您知道当 readyS
tate
是 4 (即加载! 您仍应检查和适当响应请求的状态代码,以确保其为 200 OK,而不是 500(内部服务器错误)或 404(未找到)或其他任何内容。
xhr.send(表单数据);
这里最好的技巧是 XHR 自动将发布的数据的编码设置为多部
分/表单数据
。 此编码允许服务器读取和保存文件。 这与在电子邮件中发送附件时使用的编码一样。
向用户提供反馈#
XHR2 现在 (翻转'最后) 附带
一个进
度事件。 因此,如果您通过 XHR 发送或检索大型文件,您可以告诉用户您有多远。
这很简单。 如果要跟踪 XHR 请求的进度,请收听
进度
事件。 一个让我担心了一段时间的哥查: 我需要跟踪上传的进度, 而不是下载。 要正确执行此操作,您需要侦听 XHR 上传对象的进度,如下:
xhr. upload. on 进步 = 函数 (事件) = 如果 (事件. 长度可计算) = var 完成 = (事件. 加载 / 事件. 总计 * 100 | 0); 进度. 值 = 进度. 内HTML = 完成; } };xhr. onload = 函数 () = // 以防我们被困在 99% 的进度上。
事件的
反馈请注意,我们使用 xhr.upl
oad.onprog
es 而不是
xhr.onprogresss
。 当此事件触发时,我们检查该事件是否支持计算上传的数据量(可
加分可计算
部分),然后计算完成的数据量。
在我的 HTML 中
,我使用
一个元素(类似于元素,
但在演
示任务的进度时在语义上更合适<progress><meter>)向用户显示其文件的上传量:</meter> </progress>
<progress id="progress" min="0" max="100" value="0">0</progress>
请注意,我使用内部HT
ML的浏览
器,尚不支持<progress>。</pr
ogress
> 然后,随着CSS生成的一小段时间
的内容
,内
部H
TML和进步的价值都可以是相同的(也许是过度优化,但我当时为自己感到骄傲!
最后,渲染预览#
作为一个很好的补充,我们将给用户一个预览,我们正在为他们上传。 它需要文件 API , 特别是文件阅读
器 AP
I 。
由于拖放操作(或输入)包
含文[type=file]
件对象,我们可以将其交给 FileR
eade
r 以获取文件的内容。 如果它像图像一样,我们可以获取 Base64 数据并给用户预览。 或者,如果是文本,我们可以在<div>.</
div
> 文件的 MIME 类型作为文
件
对象的类型属性可用。
因此,让我们假设我们只接受图像。 下面是浏览器收到文件后运行的预览部分:
var 接受类型 = =="图像/png":true,"图像/jpeg":true,"图像/gif":true =如果 (接受类型 = tr[file.type]ue) = var 读取器 = 新的 FileReader (); 读取器.onload = 函数 (事件) = var 图像 = 新图像 (; image.src = 事件.目标.结果; image.宽度 = 100;假调整大小文档. body. appendChild (图片); }; 阅读器.readAsDataURL(文件);}
我们创建文
件阅读器
,并给它一个文件阅读。 在上面的示例中,我使用了
readA
sDataURL,但您也可以读取纯文本和二进制格式的文件(根据规范)。
当读取器读取文件且数据可用时,它将触发loa
d
事件,从而创建我们的新图像。
文件读取操作的结果在 event.target.r
esultprope
rty 中。 在 readAsD
ataURL
的情况下,该值是沿着数据线:图像/
png;base64,ABC
.
使用棚中的所有工具#
对于我想写的文章,这个示例可能有点精心准备。 我使用许多不同的技术来做一些在网络上相当常见的模式。 事实上,这是因为我很难找到一个明确的来源上传到实际服务器(除了,当然,我写这篇文章,我发现这个例子早在2010年晚些时候!
希望您会看到每个技术项如何协同工作以创建应用程序,但同样,我希望您能够看到,如果没有或只是某些技术不可用,这会在哪里工作。 请确保检测到功能。 请确保提供回退。 确保你负责任地发展。
这里是最后的拖放和上传演示,供您玩。