HTML5应用之文件上传


Posted in HTML / CSS onDecember 30, 2016

长期以来,开发者们一直为此苦恼,大部分为解决这个问题都采用了flash作为解决方案,但flash并非灵丹妙药,因为flash版本,割据造成的问题有时反倒成为了噩梦。有些网站则采用了form标签的enctype=multipart/form-data属性,但这一属性要求服务器作出特殊的设置才能够显示进度,而且本身也比较复杂,复杂就意味着容易出现错误,这可不是我们想要的。

现在我们来看看Html5为什么能够解决这个问题,以及,它到底能做的多好。

用HTML5上传文件

在HTML5标准中,XMLHttpRequest对象被重新定义,被称为“XMLHttpRequest Level 2”,其中包含了以下5个新特性:

1、支持上传、下载字节流,比如文件、blob以及表单数据

2、增加了上传、下载中的进度事件

3、跨域请求的支持

4、允许发送匿名请求(即不发送HTTP的Referer部分)

5、允许设置请求的超时

在这篇教程中,我们主要关注第一和第二项特性,尤其是第二项——它能够提供我们想要的上传进度。和之前的方案不同,这个方案并不要求服务器作出特殊的设置,因此大家边看教程就可以边动手试试了。

HTML5应用之文件上传

HTML5应用之文件上传

上面图示的就是我们能够实现的内容:

1、显示上传的文件信息,比如文件名、类型、尺寸

2、一个能够显示真实进度的进度条

3、上传的速度

4、剩余时间的估算

5、已上传的数据量

6、上传结束后服务器返回的响应

另外,凭借XMLHttpRequest,我们的上传过程整个都是异步的,因此用户在上传文件的时候,依然可以操作网页当中的其它元素,并不需要专门等待上传的完成。而在上传结束后,我们能够获取服务器发回的响应,因此整个上传过程都显得相当顺理成章。

HTML5的进度事件

HTML5当中新增了一个进度事件(Progress Events),这个事件为我们提供了以下信息:

1、total – 文件大小

2、loaded – 已上传的大小

3、lengthComputable – 进度是否可计算

信息并不多,但是在计算文件进度上已经足够了。当然,也还有很多东西它没有直接给出,这非常遗憾。

HTML

与普通的文件上传代码并没有太大差异。不过注意,input标签关联了一个JavaScript函数在onchange上。

<!DOCTYPE html>
<html>
<head>
    <title>使用XMLHttpRequest上传文件</title>
</head>
<body>
<form id="form1" enctype="multipart/form-data" method="post" action="upload.php">
<div class="row">
      <label for="fileToUpload">Select a File to Upload</label>
<input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>
    </div>
<div id="fileName"></div>
<div id="fileSize"></div>
<div id="fileType"></div>
<div class="row">
<input type="button" onclick="uploadFile()" value="Upload" />
    </div>
<div id="progressNumber"></div>
</form>

</body>
</html>

JavaScript

一旦我们在HTML中使用了input,我们就可以在JS代码中获取到一个FileList对象。这个对象是HTML5中新增加的文件API中的一部分,每一个FileList对象都是一组文件对象的集合,而文件对象则拥有下列的属性:

1、name – 文件名(不包含路径)

2、type – 文件的MIME类型(小写)

3、size – 文件的尺寸(单位为字节)

这正是我们所需要的。当然,HTML5中还有一个FileReader对象,但在这里我们并没有用它。现在,通过上面的三个内容,我们已经能够控制用户上传的文件大小和文件类型,以便减轻服务器再次检测时的压力,并提升安全系数。

function fileSelected() {
  var file = document.getElementById('fileToUpload').files[0];
  if (file) {
    var fileSize = 0;
    if (file.size > 1024 * 1024)
      fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
    else
      fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';

    document.getElementById('fileName').innerHTML = 'Name: ' + file.name;
    document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;
    document.getElementById('fileType').innerHTML = 'Type: ' + file.type;
  }
}

那么当用户选择好文件,点击上传之后,又将发生什么呢?

function uploadFile() {
  var xhr = new XMLHttpRequest();
  var fd = document.getElementById('form1').getFormData();

  /* event listners */
  xhr.upload.addEventListener("progress", uploadProgress, false);
  xhr.addEventListener("load", uploadComplete, false);
  xhr.addEventListener("error", uploadFailed, false);
  xhr.addEventListener("abort", uploadCanceled, false);
  /* Be sure to change the url below to the url of your upload server side script */
  xhr.open("POST", "upload.php");
  xhr.send(fd);
}

function uploadProgress(evt) {
  if (evt.lengthComputable) {
    var percentComplete = Math.round(evt.loaded * 100 / evt.total);
    document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
  }
  else {
    document.getElementById('progressNumber').innerHTML = 'unable to compute';
  }
}

function uploadComplete(evt) {
  /* This event is raised when the server send back a response */
  alert(evt.target.responseText);
}

function uploadFailed(evt) {
  alert("There was an error attempting to upload the file.");
}

function uploadCanceled(evt) {
  alert("The upload has been canceled by the user or the browser dropped the connection.");
}

在代码的第二行中,我们的JS代码又使用了另一个HTML5推出的新对象——FormData。FormData对象是用户的表单数据的集合,它以键值对的形式存储了表单数据,其值能够包括数字、字符串以及文件。我们通过辗转这个对象,来向服务器提交数据。

当然,这个对象我们也可以在代码中手工构建,比如说像下面这样:

var fd = new FormData();
fd.append("author", "Shiv Kumar");
fd.append("name", "Html 5 File API/FormData");
fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);

回到正题。回顾上一段代码,我们增加了许多有关XMLHttpRequest的事件监听,其目的是为了获取文件上传的真实情况。尤其需要注意的是,我们所挂钩的,并不是XMLHttpRequest本身,而是其属性,比如uploadProgress。

完整代码

最后,来看看完整的代码。

<!DOCTYPE html>
<html>
<head>
    <title>Upload Files using XMLHttpRequest - Minimal</title>

    <script type="text/javascript">
      function fileSelected() {
        var file = document.getElementById('fileToUpload').files[0];
        if (file) {
          var fileSize = 0;
          if (file.size > 1024 * 1024)
            fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
          else
            fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';

          document.getElementById('fileName').innerHTML = 'Name: ' + file.name;
          document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;
          document.getElementById('fileType').innerHTML = 'Type: ' + file.type;
        }
      }

      function uploadFile() {
        var fd = new FormData();
        fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
        var xhr = new XMLHttpRequest();
        xhr.upload.addEventListener("progress", uploadProgress, false);
        xhr.addEventListener("load", uploadComplete, false);
        xhr.addEventListener("error", uploadFailed, false);
        xhr.addEventListener("abort", uploadCanceled, false);
        xhr.open("POST", "UploadMinimal.aspx");
        xhr.send(fd);
      }

      function uploadProgress(evt) {
        if (evt.lengthComputable) {
          var percentComplete = Math.round(evt.loaded * 100 / evt.total);
          document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
        }
        else {
          document.getElementById('progressNumber').innerHTML = 'unable to compute';
        }
      }

      function uploadComplete(evt) {
        /* This event is raised when the server send back a response */
        alert(evt.target.responseText);
      }

      function uploadFailed(evt) {
        alert("There was an error attempting to upload the file.");
      }

      function uploadCanceled(evt) {
        alert("The upload has been canceled by the user or the browser dropped the connection.");
      }
    </script>
</head>
<body>
<form id="form1" enctype="multipart/form-data" method="post" action="upload.php">
<div class="row">
      <label for="fileToUpload">Select a File to Upload</label>
<input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>
    </div>
<div id="fileName"></div>
<div id="fileSize"></div>
<div id="fileType"></div>
<div class="row">
<input type="button" onclick="uploadFile()" value="Upload" />
    </div>
<div id="progressNumber"></div>
</form>

</body>
</html>

我们的任务完成了吗?可以说完成了,因为这段代码已经能够完成上传文件的任务,而且也能够显示上传的进度;但是理应说我们没有,因为除了这个骨架HTML之外,我们还有很多没有做的事情,比如CSS的美化等等。不过这就不是我们这篇文章的主题了。

最后,提醒一下,教程的代码应当在支持新特性的浏览器之上运行,如果你不清楚自己的浏览器是否支持,可以在这里查询。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

HTML / CSS 相关文章推荐
收集的22款给力的HTML5和CSS3帮助工具
Sep 14 HTML / CSS
HTML5拖放功能_动力节点Java学院整理
Jul 13 HTML / CSS
整理的15个非常有用的 HTML5 开发教程和速查手册
Oct 18 HTML / CSS
html5 Canvas画图教程(6)—canvas里画曲线之arcTo方法
Jan 09 HTML / CSS
详解HTML5中表单验证的8种方法介绍
Dec 19 HTML / CSS
HTML5拖拉上传文件的简单实例
Jan 11 HTML / CSS
HTML5新特性之语义化标签
Oct 31 HTML / CSS
如何用canvas实现在线签名的示例代码
Jul 10 HTML / CSS
遮罩层 + Iframe实现界面自动显示的示例代码
Apr 26 HTML / CSS
video下autoplay属性无效的解决方法(添加muted属性)
May 19 HTML / CSS
清除canvas画布内容(点擦除+线擦除)
Aug 12 HTML / CSS
html form表单基础入门案例讲解
Jul 21 HTML / CSS
详解HTML5中的标签
Jun 19 #HTML / CSS
HTML5 Canvas实现玫瑰曲线和心形图案的代码实例
Apr 10 #HTML / CSS
使用HTML5捕捉音频与视频信息概述及实例
Aug 22 #HTML / CSS
CSS3只让背景图片旋转180度的实现示例
Mar 09 #HTML / CSS
CSS3 真的会替代 SCSS 吗
Mar 09 #HTML / CSS
css3实现书本翻页效果的示例代码
Mar 08 #HTML / CSS
纯CSS3实现圆圈动态发光特效动画的示例代码
Mar 08 #HTML / CSS
You might like
《PHP边学边教》(02.Apache+PHP环境配置――上篇)
2006/12/13 PHP
php连接数据库代码应用分析
2011/05/29 PHP
深入解析php中的foreach函数
2013/08/31 PHP
PHP使用GIFEncoder类生成的GIF动态图片验证码
2014/07/01 PHP
使用WordPress发送电子邮件的相关PHP函数用法解析
2015/12/15 PHP
Ajax+PHP实现的删除数据功能示例
2019/02/12 PHP
用CSS+JS实现的进度条效果效果
2007/06/05 Javascript
cnblogs csdn 代码运行框实现代码
2009/11/02 Javascript
jqeury eval将字符串转换json的方法
2011/01/20 Javascript
JQuery实现倒计时按钮具体方法
2013/11/14 Javascript
CascadeView级联组件实现思路详解(分离思想和单链表)
2016/04/12 Javascript
JavaScript入门教程之引用类型
2016/05/04 Javascript
Ajax使用原生态JS验证用户名是否存在
2020/05/26 Javascript
JS正则截取两个字符串之间及字符串前后内容的方法
2017/01/06 Javascript
使用jquery判断一个元素是否含有一个指定的类(class)实例
2017/02/12 Javascript
ES6学习笔记之Set和Map数据结构详解
2017/04/07 Javascript
详解AngularJs路由之Ui-router-resolve(预加载)
2017/06/13 Javascript
深入理解 webpack 文件打包机制(小结)
2018/01/08 Javascript
微信小程序云开发详细教程
2019/05/16 Javascript
jQuery属性选择器用法实例分析
2019/06/28 jQuery
一次微信小程序内地图的使用实战记录
2019/09/09 Javascript
[49:35]2018DOTA2亚洲邀请赛3月30日 小组赛A组 KG VS TNC
2018/03/31 DOTA
python pickle 和 shelve模块的用法
2013/09/16 Python
python获取豆瓣电影简介代码分享
2014/01/16 Python
Python调用ctypes使用C函数printf的方法
2017/08/23 Python
python3 发送任意文件邮件的实例
2018/01/23 Python
Python+selenium实现自动循环扔QQ邮箱漂流瓶
2018/05/29 Python
Python利用imshow制作自定义渐变填充柱状图(colorbar)
2020/12/10 Python
html5 input元素新特性_动力节点Java学院整理
2017/07/06 HTML / CSS
意大利奢侈品综合电商网站:MODES
2019/12/14 全球购物
车贷收入证明范本
2014/01/09 职场文书
公司离职证明范本
2014/01/13 职场文书
拯救大兵瑞恩观后感
2015/06/09 职场文书
2016学习全国教书育人楷模先进事迹心得体会
2016/01/21 职场文书
详解Django的MVT设计模式
2021/04/29 Python
MySQL数据库之存储过程 procedure
2022/06/16 MySQL