利用FormData对象 + XHR 新特性实现文件上传——带进度条

Posted 啵啵丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用FormData对象 + XHR 新特性实现文件上传——带进度条相关的知识,希望对你有一定的参考价值。

小编今天又get到一个新技能,就是上传图片并显示进度条,话不多说,直接进入正题!冲冲冲!!💪

实现效果:

当点击上传文件按钮后,如果未选择文件,会跳出请选择要上传的文件提示框,反之,会有一个上传图片的进度条显示,当上传完成后,图片也会对应的显示在页面中.

 

 实现步骤:

 ① 定义UI 结构

 ② 验证是否选择了文件

 ③ 向 FormData 中追加文件

 ④ 使用 xhr 发起上传文件的请求

 ⑤ 监听 onreadystatechange请求

 ⑥ 显示文件上传进度

 ⑦ 基于 bootstrap 绘制进度条效果

 ⑧ 监听上传完整的事件

 【接下来我会根据实现步骤来一一说明,最后会附上完整代码,认真看哟~ 】

分步解析: 

① 定义UI 结构 

 先引入相关的文件,bootstrap.cssjQuery.min.js 

 开始布局页面基本结构(代码如下图所示)

 其中进度条的样式是从bootstrap官网——>组件——>进度条中挑选的

 最后给一个 Img 标签用来显示上传到服务器的图片

    <!-- 文件选择框 --> 
<input type="file" id="file1"> 
    <button id="btn">上传文件</button>
    <br>
    <!-- 引用 bootstrap中的进度条 -->
    <div class="progress" style="width: 500px; margin: 15px 10px">
        <div class="progress-bar progress-bar-striped active"style="width: 0" id="percent">
         0
        </div>
      </div>
     <!--显示上传到服务器的图片-->
 <img src="" alt="" id="img" width="800">

② 验证是否选择了文件

  先获取到上传文件的按钮并为它添加点击事件

  获取到选择的文件列表(files)

  其中 var files = document.querySelector('#file1').files
  通过id获取文件选择框,在文件选择框中有一个 files 属性,它是一个数组,里面存放用户      选择的文件,判断 它的length是否小于等于0,如果是,则没有选择文件

<script>  
          // 1.获取上传文件的按钮
        var btn = document.querySelector('#btn')
            // 2.为按钮添加 click 事件监听
        btn.addEventListener('click',function(){
            // 3.获取到选择的文件列表
            var files = document.querySelector('#file1').files
            if(files.length <= 0) {
                return alert('请选择要上传的文件!')
            }
           
         }
</script>

③ 向 FormData 中追加文件

 Ajax 操作往往用来提交表单数据。为了方便表单处理,html5新增一个 formData 对象,可 以模拟表单操作

通过 append 就可以向 FormData 中追加文件  

   //1. 创建 FormData 对象
   var fd = new FormData()
   //2. 向 FormData 中追加文件,('自定义文件名',文件),因为是一个数组,取第一个文件所以索引为0
   fd.append('avatar',files[0])

④  使用 xhr 发起上传文件的请求

 XMLHttpRequest(简称 xhr) 是浏览器提供的 javascript 对象,通过它,可以 请求服务器上   的数据资源

 创建完 xhr 对象后,通过调用 open 函数,指定 请求方式URL地址

 这里需要注意!因为是上传文件,所以请求方式必须为 post

 调用 send 函数,发起 Ajax 请求

  // 1. 创建 xhr 对象
  var xhr = new XMLHttpRequest()
  // 2. 调用 open 函数,指定请求类型与URL地址。其中,请求类型必须为 post
  xhr.open('POST','http://www.liulongbin.top:3006/api/upload/avatar')
  // 3. 发起请求
  xhr.send(fd)

 ⑤ 监听 onreadystatechange 请求

 监听 xhr 对象的 请求状态 readyState; 与服务器的 响应状态 status

 如果 xhr.readyState 全等于 4 且 xhr.status 全等于 200 ,就获取从服务器响应回来的数据

 并把它转换为 JS 对象(方便后续获取里面的值) 存放在 自定义的 data 对象中

 获取到的 data 数据中有很多的属性,其中 data.status 代表上传的状态,如果为 200则表示上传成功

如果上传成功就把上传的图片显示在页面中

xhr 对象的 readyState 属性

状态描述
0UNSENTXMLHttpRequest 对象已被创建,但尚未调用 open() 方法
1OPENEDopen() 方法已经被调用
2HEADERS_RECEIVEDsend() 方法已经被调用,响应头也已经被接收
3LOADING数据接收中,此时 response 属性中已经包含部分数据
4DONEAjax 请求完成,这意味着数据传输已经彻底完成失败
xhr.onreadystatechange = function() {
 if(xhr.readyState === 4 && xhr.status === 200) {
  var data = JSON.parse(xhr.responseText)
   if(data.status === 200) {
    // 上传成功
    // 将服务器返回的图片地址,设置为 <img> 标签的 src 属性
    document.querySelector('#img').src = 'http://www.liulongbin.top:3006' + data.url

     } else {
                  // 上传失败
                  console.log('图片上传失败!' + data.message);
            }
 }
}

⑥ 显示文件上传进度

 新版本的 XHLHttpRequest 对象中,可以通过监听 xhr.upload.onprogress 事件,来获取   到文件的上传进度

 //做文件上传的进度
 xhr.upload.onprogress = function(e) {
   //e.lengthComputable 是一个布尔值,表示当前上传的资源是否具有可计算的长度
   if(e.lengthComputable) {
     // e.loaded 已传输的字节
     // e.total 需传输的总字节
     var percentComplete = Math.ceil((e.loaded/e.total) * 100)
                   
      }
}

⑦  基于 bootstraps 绘制进度条效果

把算出的上传进度的百分比赋值给从 bootstrap 中引入的模板中,从而实现将进度绘制到页面 

//将进度渲染到页面
$('#percent').attr('style','width:' + percentComplete + '%;').html(percentComplete + '%')

⑧ 监听上传完整的事件 

通过监听 xhr.upload.onload  事件来表示文件是否上传完整,上传完整后,将进度条修改为绿色

  xhr.upload.onload = function() {
      // 移除当前样式,添加 新样式
     $('#percent').removeClass().addClass('progress-bar progress-bar-success')
  }

完整代码 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../bootstrap.css">
    <script src="../jQuery.min.js"></script>
</head>
<body>
    <input type="file" id="file1">
    <button id="btn">上传文件</button>
    <br>
    <!-- bootstrap中的进度条 -->
    <div class="progress" style="width: 500px; margin: 15px 10px">
        <div class="progress-bar progress-bar-striped active"style="width: 0" id="percent">
         0
        </div>
      </div>

    <img src="" alt="" id="img" width="800">
    <script>
        // 1.获取上传文件的按钮
        var btn = document.querySelector('#btn')
        // 2.为按钮添加 click 事件监听
        btn.addEventListener('click',function(){
            // 3.获取到选择的文件列表
            var files = document.querySelector('#file1').files
            if(files.length <= 0) {
                return alert('请选择要上传的文件!')
            }
            //1. 创建 FormData 对象
            var fd = new FormData()
            //2. 向 FormData 中追加文件
            fd.append('avatar',files[0])

            var xhr = new XMLHttpRequest()
            //做文件上传的进度
            xhr.upload.onprogress = function(e) {
                //e.lengthComputable 是一个布尔值,表示当前上传的资源是否具有可计算的长度
                if(e.lengthComputable) {
                    // e.loaded 已传输的字节
                    // e.total 需传输的总字节
                    var percentComplete = Math.ceil((e.loaded/e.total) * 100)
                    //将进度渲染到页面
                    $('#percent').attr('style','width:' + percentComplete + '%;').html(percentComplete + '%')
                   
                }
            }
            xhr.upload.onload = function() {
                $('#percent').removeClass().addClass('progress-bar progress-bar-success')
            }
            xhr.open('POST','http://www.liulongbin.top:3006/api/upload/avatar')
            xhr.send(fd)
            xhr.onreadystatechange = function() {
                if(xhr.readyState === 4 && xhr.status === 200) {
                    var data = JSON.parse(xhr.responseText)
                    if(data.status === 200) {
                        // 上传成功
                        // 将服务器返回的图片地址,设置为 <img> 标签的 src 属性
                        document.querySelector('#img').src = 'http://www.liulongbin.top:3006' + data.url

                    } else {
                        // 上传失败
                        console.log('图片上传失败!' + data.message);
                    }
                }
            }
        })
    </script>
</body>
</html>


这次的分享到这就结束啦~大家快去试试把! 

以上是关于利用FormData对象 + XHR 新特性实现文件上传——带进度条的主要内容,如果未能解决你的问题,请参考以下文章

如何将 enctype 属性添加到 FormData() 对象?

php 下 html5 XHR2 + FormData + File API 上传文件

如何实现一个进度条,显示我用xhr函数上传%

使用XHR上传文件要不要了解一下?

使用原生xhr实现上传文件功能

ajax 利用formdata对象 实现多文件上传