文件上传(显示进度条、上传速度)

XMLHttpRequest对象

使用XMLHttpRequest对象实现数据交互。

//创建XMLHttpRequest对象
let xhr = new XMLHttpRequest(); //let来创建(ES6版本以上)

//为了应对所有的现代浏览器,检查浏览器是否支持 XMLHttpRequest 对象。
//如果支持,则创建XMLHttpRequest对象。如果不支持,则创建 ActiveXObject
var xmlhttp;
if (window.XMLHttpRequest){ 
// IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else{ 
  // IE5, IE6
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }

XMLHttpRequest对象有三个重要属性:
1、onreadystatechange
onreadystatechange:存有处理服务器响应的函数,每当 readyState 改变时,onreadystatechange 函数就会被执行。
2、readyState:存有服务器响应的状态信息。从0到4的变化

  • 0: 请求未初始化(代理被创建,但尚未调用 open方法)
  • 1: 服务器连接已建立(open方法已经被调用)
  • 2: 请求已接收(send方法已被调用,且头部和状态已经可获得)
  • 3: 请求处理中(下载中,responseText 属性已经包含部分数据)
  • 4: 请求已完成,且响应已就绪(下载操作已完成)

3、status:服务器响应状态码

  • 200 :OK
  • 404 : 未找到页面
//当 readyState 等于 4 且状态为 200 时,表示响应已就绪。举例如下:
let xhr = new XMLHttpRequest();
xhr.onreadystatechange=function(){ 
  if (xhr.readyState==4 && xhr.status==200){ 
    document.getElementById("myDiv").innerHTML=xhr.responseText;
   }
 }

向服务器发送请求,使用XMLHttpRequest对象的open()send()方法

let xhr = new XMLHttpRequest();
/* open(method,url,async)方法: 参数method:请求的类型get或者post 参数url:文件在服务器上的位置 参数async:true为异步或者false为同步 */
xhr.open("get","/fileUpload",true);
// send()方法:将请求发送给服务器,如果send方法带参数,只能用于post请求
xhr.send();

post和get请求类型怎么选择?
get比post更简单也更快,并且在大部分情况下都能用。

GET:一般用于信息获取,使用 URL 传递参数,对所发送信息的数量也有限制,一般在2000 个字符
POST:一般用于修改服务器上的资源,对所发送的信息没有限制
也就是说 Get 是通过地址栏来传值,而 Post 是通过提交表单来传值。
在以下情况中,请使用 POST 请求:

  1. 无法使用缓存文件(更新服务器上的文件或数据库)
  2. 向服务器发送大量数据(POST 没有数据量限制)
  3. 发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

FormData对象

使用FormData对象上传文件

 <input type="file" class="myfile">
 进度<progress max="100" value="0"></progress>
 <span class="persent">0%</span>
 速度 <span class="speed">0b/s</span>
 <button class="btn">上传文件</button>
 <button class="btn">取消文件</button>
 <div class="boxFile"></div>
 <script>
     let file = document.querySelector(".myfile").files[0];
     console.log(file);
     let form = new FormData(); //实例化FormData对象 
     // 向form中添加新的属性值,如果对应的属性值存在也不会覆盖原值,而是新增一个值,
     // 如果属性不存在则新增一项属性值。
     form.append("myfiles",file);//myfiles是文件上传时对应的自定义名称 
 </script>

前面讲了上传文件时显示进度条,继续加上新功能显示上传速度;

完整代码如下:
项目主目录myProject下的index.js

const Koa = require("koa");
const static = require("koa-static");
const Router = require("koa-router");
const koaBody = require("koa-body");
const fs = require("fs");
const path = require("path");
/* path.join()方法: 使用平台特定的分隔符把全部给定的 path 片段连接到一起,并规范化生成的路径。 长度为零的 path片段会被忽略。如果连接后的路径字符串是一个长度为零的字符串,则返回 '.',表示当前工作目录。 */
let app = new Koa();
let router = new Router();

app.use(koaBody({ 
    // 允许文件上传(必须设置)
    multipart:true
}));

app.use(static(path.join(__dirname,"/static")));

router.get("/",ctx=>{ 
    ctx.body = "开始使用ajax";
});

// 文件上传
router.post("/fileUpload",ctx=>{ 
    //console.log(ctx.request.files.myfiles);
    let fileData = fs.readFileSync(ctx.request.files.myfiles.path);
    // 上传后的文件及图片都在 myProject/static/uploadFile下
 fs.writeFileSync(path.join("static","uploadFile",ctx.request.files.myfiles.name),fileData);
    ctx.body = path.join("uploadFile",ctx.request.files.myfiles.name);
});

app.use(router.routes());//启动路由
app.listen(8000);//设置端口号

项目myProject下的static目录下的progress.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>上传文件(显示进度与速度)</title>
    <style>
        .boxFile { 
            width: 645px;
            height: 500px;
        }
        img { 
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <input type="file" class="myfile">
    进度<progress max="100" value="0"></progress>
    <span class="persent">0%</span>
    速度 <span class="speed">0b/s</span>
    <button class="btn">上传文件</button>
    <button class="btn">取消文件</button>
    <div class="boxFile"></div>
    <script>
        // XMLHttpRequest 对象用于在后台与服务器交换数据。
        // 实例化 XMLHttpRequest 对象
        let xhr = new XMLHttpRequest();
        let stime; //存储时间
        let sloaded; // 存储上传的内容
        let btns = document.querySelectorAll(".btn");
        // 点击"上传文件"
        btns[0].onclick = function () { 
            let file = document.querySelector(".myfile").files[0];//
            console.log(file);
            let form = new FormData(); //实例化FormData对象
            
            // 向form中添加新的属性值,如果对应的属性值存在也不会覆盖原值,而是新增一个值,
            // 如果属性不存在则新增一项属性值。
            form.append("myfiles", file); 

            xhr.open("post", "/fileUpload",true); //初始化请求

            xhr.onload = function () { 
                console.log(xhr.responseText);
            }
            /* onreadystatechange:存有处理服务器响应的函数,每当 readyState 改变时, 函数就会被执行。readyState:存有服务器响应的状态信息。status存响应状态码*/
            xhr.onreadystatechange = function () { 
                if (xhr.readyState == 4 && xhr.status == 200) { 
                    let resText = xhr.responseText;
                    let imgEl = document.createElement("img");
                    imgEl.src = resText;
                    imgEl.onload = function () { 
                        // document.body.appendChild(this);//上传图片后,页面会出现两张一样的图片
                        document.querySelector(".boxFile").appendChild(this); //img标签外面加一个父级div标签就好了
                    }
                }
            }

            xhr.upload.onloadstart = function () { 
                console.log("开始上传");
                stime = new Date().getTime();
                sloaded = 0;
            }
            xhr.upload.onprogress = function (evt) { 
                console.log("上传中......");
                // 当前上传文件的文件大小:evt.loaded
                // 需要上传的总文件的大小:evt.total
                // 上传进度
                //上传文件的百分比
                //toFixed(参数):保留几位小数 参数是整型的数值,数值是几就保留几位小数
                let persent = ((evt.loaded / evt.total) * 100).toFixed(0);   
                document.querySelector("progress").value = persent;
                document.querySelector(".persent").innerHTML = persent + "%";

                // 上传速度
                // 上传结束时间
                let endTime = new Date().getTime();

                // 1、时间差(时间段)
                let dTime = (endTime - stime) / 1000; //毫秒换算成秒

                // 2、当前时间段内上传的文件大小
                let dloaded = evt.loaded - sloaded;

                // 3、当前速度= 当前上传文件的内容/当前时间差
                let speed = dloaded / dTime;

                // 重置上传开始时间与文件大小(分时段上传的)
                stime = new Date().getTime();
                sloaded = evt.loaded;

                // 基本单位:字节b
                // 1mb=1024kb 1kb=1024b
                // b/s
                let unit = "b/s"; //不足1kb,以b/s来计算速度
                // kb/s
                if (speed / 1024 > 1) {  //当大小超过1024b(即1kb时),以kb/s来计算速度
                    unit = "kb/s";
                    speed = speed / 1024;
                }
                // mb/s 
                if (speed / 1024 > 1) {  //当大小超过1024Kb(即1mb时),以mb/s来计算速度
                    unit = "mb/s";
                    speed = speed / 1024;
                }
                document.querySelector(".speed").innerHTML = speed.toFixed(2) + unit;
            }
            xhr.upload.onload = function () { 
                console.log("上传成功");
            }
            xhr.upload.onerror = function () { 
                console.log("上传失败");
            }
            xhr.send(form);//发送请求
        }
        // 点击"取消上传"
        // xhr.abort():终止请求,调用后即可取消文件上传操作
        btns[1].onclick = function () { 
            xhr.abort();
        }
    </script>
</body>
</html>
    原文作者:此鱼非闲鱼也
    原文地址: https://blog.csdn.net/m0_45315697/article/details/105252334
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞