这个演示是由 Olli Pettay(smaug)在 Austin King 的帮助下完成的。
当今网络上一个常见的局限性是缺乏用于 Web 应用程序的丰富的文件上传小部件。许多网站使用 Flash 或桌面辅助应用程序来改善文件上传体验。
Firefox 3.5 弥合了这些差距之一,允许构建更好的进度指示器。许多开发人员没有意识到他们可以使用 Firefox 的 File 对象(nsIDOMFile)和 XMLHttpRequest 一起完成文件上传。这个演示将展示一个上传小部件,它提供了用户期望的那种丰富的进度反馈,以及快速简便的多文件同时上传。
进度指示器
向用户提供应用程序正在为他们努力工作的反馈信息总是好的,特别是当当前操作预计何时完成时。主要有两种类型的进度反馈:
- 不确定进度 - 某些活动刚刚发生
- 确定性进度 - 我完成了 40%,我完成了 42% …… 等等
确定性进度?演示
我们创建了一个简单的文件上传/下载页面,演示了进度条
演示托管在 mozilla.pettay.fi,需要 Firefox 3.5 beta4 或更高版本。它演示了如何执行多文件同时上传,无需提交表单或离开当前页面。对于每个文件上传/下载,我们显示当前速度、完成百分比和已传输字节数。我们将回顾代码中的一些关键片段,这些片段在上面的屏幕截图中使用。请点击 演示 并查看源代码以获取完整的代码示例。
该页面包含两个 HTML 输入,一个 type="file"
和一个 type="button"
。表单实际上从未提交,而是向按钮添加了一个 onclick 处理程序
<input type="file" id="file">
<input type="button"
onclick="startXHR();"
value="Upload file using XHR">
在 startXHR 函数中,我们创建了一个 XMLHttpRequest 并向 XHR 请求添加了一个事件处理程序,以监听新的“进度”事件。使用此 ProgressEvent 的 lengthComputable 属性,我们将知道我们是否正在处理不确定进度或确定性进度。该对象还提供了已加载和总字节数。
var xhr = new XMLHttpRequest();
xhr.onprogress = function(evt) {
if (evt.lengthComputable) {
evt.target.curLoad = evt.loaded;
evt.target.log.parentNode.parentNode.previousSibling.textContent =
Number(evt.loaded/k).toFixed() + "/"+ Number(evt.total/k).toFixed() + "kB";
}
if (evt.lengthComputable) {
var loaded = (evt.loaded / evt.total);
if (loaded < 1) {
var newW = loaded * width;
if (newW < 10) newW = 10;
evt.target.log.style.width = newW + "px";
}
}
};
现在我们需要一些要发送的数据。我们通过 ID 直接从输入中获取文件内容
var files = document.getElementById("file").files;
if (files) {
var file = files.item(0);
xhr.sendAsBinary(file.getAsBinary());
最后一步是启动请求
xhr.open("POST", "cgi-bin/posthandler.pl");
xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
xhr.sendAsBinary(file.getAsBinary());
这些方法也适用于 xhr.upload.onprogress
。
注意在 sendAsBinary 方法上使用 XMLHttpRequest 对象和 getAsBinary 方法在 File 对象上。从 Firefox 3 开始,您可以在不提交表单的情况下获取客户端上文件的內容。这对超越传统文件输入和表单提交的局限性非常有用。它也是即将推出的 W3C 标准 的一部分,用于文件上传。
nsIDOMFile 提供的另一个相关方法是 getAsText 方法,它返回一个 DOMString,适合切片、切块和显示。
这是一个示例用法,演示中没有使用
file.getAsText("utf8");
这就是代码的要点。查看 演示及其源代码。
用户界面中的反馈
向用户公开系统反馈可以提高感知性能。我们
无法始终确定某些操作需要多长时间,因此至少我们
可以显示不确定进度。
在文件上传和文件下载期间(假设服务器提供了 Content-Length
),我们确实知道总字节数。Firefox 3.5 的进度事件支持添加了一个进度事件,以便我们可以显示实际的上传/下载进度。
传统上,从 XMLHttpRequests 获取确定性进度很困难。理论上,您可以为其提供回调并观察状态码更新和文本消息更新,但在实践中,它们并不十分有用。在过去,如果确定性进度计很重要,您将不得不发出第二个 XHR 请求来轮询进度。
引入进度事件
W3C 已经发布了 进度事件 1.0 的工作草案,我们将其包含在 Firefox 3.5 中。Firefox 添加了一个关键的新 DOM ProgressEvent progress 事件,以及 loadstart 事件。其他现有的事件包括:error、abort 和 load。
这些相同的事件也适用于上传和下载。进度事件提供了以下属性
- lengthComputable - true 或 false,请求的大小是否已知?
- loaded - 到目前为止已接收的字节数
- total - 整个请求的预期字节数
契约
当您查看这些进度事件的属性时,会应用某些规则,您可以依赖这些规则。它们是
- 当 lengthComputable 为 false 时,total 属性将为 0。
- loadstart 事件始终只发出一次信号。
- 进度事件在 loadstart 之后被触发零次或多次。
就是这样。使用 Firefox 3.5 的强大功能,开始改进文件上传吧。
关于 Austin King
位于西雅图的非教条主义艺术家/程序员型人类。应用程序工程团队的无赖 Web 开发者。拼写检查留给本周吧。
38 条评论