前后端交互一(ajax基本使用,XMLHttpRequest对象实现数据交互,onreadystatechange服务器响应信息,FormData对象上传文件,upload事件对象)

84 篇文章 3 订阅
7 篇文章 1 订阅

目录

1.重点掌握及知识要点

2.登录简单回顾

3.利用ajax来解决验证用户名问题

3.1ajax的基本使用

3.2案例实现通过ajax异步无刷新验证用户名

4.针对ajax的详细解释

4.1get注意点

4.1.1get传参的两种方式:queryString和/get/id

4.1.2queryString传参方式

4.1.3/get/id传参方式

4.2post传参方式

4.2.1post传参方式注意点

4.2.2post传参方式设置http正文头格式

4.2.3onload()方法中获取返还头部信息

4.2.4完整案例

4.3同步及异步ajax

4.4onload()

5.onreadystatechange——了解

5.1onreadystatechange

5.2readyState

5.3status常用状态码

5.4onreadystatechange示例: 

5.5onload实现onreadystatechange功能

6.返还数据类型(XML,Json) 

6.1获取原始数据xhr.response

6.2返还数据为json时xhr.responseText

6.3返还数据为json时,xhr.responseXML来获取 

7.利用FormData对象来实现文件上传

7.1 创建FormData对象

7.2 监控上传进度——upload 事件

7.2.1upload事件下的各种事件——事件钩子

7.2.2监控文件上传进度示例

8.回顾


1.重点掌握及知识要点

## 重点掌握

  1. 理解ajax基本使用
  2. 会使用XMLHttpRequest对象实现数据交互
  3. 了解onreadystatechange服务器响应信息(状态码)
  4. 会使用FormData对象上传文件
  5. 了解upload事件对象(XMLHttpRequest下的事件对象)

## 知识要点

  1. ajax使用
  2. XMLHttpRequest对象
  3. FormData对象
  4. upload 事件对象

2.登录简单回顾

  1. 提出ajax验证用户名需求;
  2. 验证错误后,如果通过跳转解决很麻烦;
  3. 各种跳转用户体验差

3.利用ajax来解决验证用户名问题

ajax是: Ajax即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML)

3.1ajax的基本使用

  • 新建XMLHttpRequest对象;
 let xhr = new XMLHttpRequest();
  • 配置请求参数
 xhr.open("get","/checkUser",true); //true是异步,false是同步
  • 接收返还值
  xhr.onload = function(){
     let res = JSON.parse(xhr.responseText);
  }
  • 发送服务器请求
xhr.send();

3.2案例实现通过ajax异步无刷新验证用户名

注意:

  1. 通过 XMLHttpRequest对象中open()方法发起请求。xhr.open("get","/checkUser?username="+this.value,true); //true表示异步发送请求,false同步发送请求,默认为false,所以必须设置为true
  2. 通过 XMLHttpRequest对象中onload()方法获取返还数据。注意返回数据是从XMLHttpRequest对象中获得的,xhr.responseText(获取json数据)和xhr.response(获取原始数据),xhr.responseXML(获取XML数据)都可以获取返还数据
  3. 获取到的数据是JSON格式的,需要将其转为对象。JSON.parse(xhr.responseText).msg
  4. 后台接收queryString参数通过cxt.query接收;如果是post普通数据传参只需引入koa-body模块,后台通过ctx.request.body接收;如果是post传参且上传文件需引入koa-bodyparser ,然后通过ctx.request.body接收

 login.css:

.loginContainer{
    margin: 0 auto;
    width: 600px;
    text-align: center;
    padding-top: 20px;
    padding-bottom: 50px;
    border: 1px solid;
}
.loginContainer input{
    margin-bottom: 20px;
}
.loginStyle{
    width: 160px;
    height: 40px;
    background: rgb(50,203,77);
    color: white;
    font-size: 17px;
}
.inputStyle{
    width: 200px;
    height: 30px;
    padding: 5px;
    outline: none;
}

.inputStyle:focus{
    border: 1px solid rgb(50,203,77);
}
form{
    position: relative;
}
.exchange{
    position: absolute;
    top:8px;
    right: 65px;
    color: red;
    display: none;
}

user.json:

[
    {
        "id":1,
        "username":"zhangsan",
        "pwd":"123"
    },{
        "id":2,
        "username":"lisi",
        "pwd":"123"
    }
]

 login.js:

const Koa = require("koa");
const Router = require("koa-router");
const static = require("koa-static");
// const views = require("koa-views");
const userData = require("./data/user.json");

let app = new Koa();
let router = new Router();

app.use(static(__dirname + "/static"));
//前面页面直接放到static里时,只能通过login.html访问,不能通过/直接访问
router.get("/checkUser", (ctx, next) => {
    // 注意接收queryString参数通过cxt.query获得;如果是post传参需引入koa-bodyparser ,然后通过ctx.request.body接收
    let username = userData.find(item=>item.username === ctx.query.username);
    console.log(ctx.query);
    if(username){
    // node.js会自动将对象转为json传给前端,所以不用再进行转换
        ctx.body = {
            status:1,
            msg:"用户名正确"
        };
    }else{
        ctx.body = {
            status:0,
            msg:"用户名错误"
        };
    }
});

app.use(router.routes());
app.listen("9090");

login.html:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <link rel="stylesheet" href="css/login.css" />
  <title>Document</title>
</head>

<body>
  <div class="loginContainer">
    <h1>登录</h1>
    <form action="/checkUser" method="post">姓名:
      <input class="inputStyle" type="text" name="username" />
      <div class="exchange">用户名错误</div>
      <br />密码:
      <input class="inputStyle" type="password" name="pwd" /><br />
      <input class="loginStyle" type="submit" value="登录" />
    </form>
  </div>
  <script>
{
  //鼠标失去焦点时,进行无刷新验证
  let username = document.querySelectorAll("input");
  let exchange = document.querySelector(".exchange");
 //使用焦点时验证用户名和密码
 
  username[0].onblur = function(){
    let xhr = new XMLHttpRequest();
    xhr.open("get","/checkUser?username="+this.value,true);//true表示异步发送请求,false同步发送请求
    xhr.onload = function() {
      //注意返回数据是从XMLHttpRequest对象中获得的,xhr.responseText和xhr.response都可以获取返还数据
      let res = JSON.parse(xhr.responseText);
      console.log(JSON.parse(xhr.responseText).msg);
      console.log(xhr.response);
      exchange.style.display = "block";
      //获取到的数据是JSON格式的,需要将其转为对象
      exchange.innerHTML = JSON.parse(xhr.responseText).msg;
      console.log(res.status);
      
      if(res.status === 1){
        exchange.style.color = "green";
      }else{
        exchange.style.color = "red";
      }
    }
     // 必须调用send()方法
    xhr.send();
  }
}
  </script>
</body>

通过http://localhost:9090/login.html即可请求道login.html页面 

4.针对ajax的详细解释

很多ajax框架都是基于XMLHttpRequest对象去实现的,但是很多框架也都存在一定问题,如axiso就不能实现文件或图片上传。

4.1get注意点

  • get通过parmas传参
  • get和querystring的问题,通过url传参

a标签,img标签中的src和script标签中的src都是使用get请求

4.1.1get传参的两种方式:queryString和/get/id

  1. queryString,通过queryString传参有长度限制,默认为2048
  2. /get/id

传参方式注意点:

  • querystring传参和get/post请求方式是两个概念,不是使用querystring传参就是get请求,post也可以通过querystring进行传参;通过ctx.query获取传递过来的参数
  • 通过querystring方式进行传参时,后台接收地址不受影响;但如果使用/get/id方式传参,后台必须通过/get/:id方式接收参数,并通过ctx.params获得参数值

4.1.2queryString传参方式

如上例。

注意queryString传参方式,通过ctx.query获取传递过来的参数。

4.1.3/get/id传参方式

传参方式:‘/请求地址/参数’ 

接收参数:‘/请求地址/:参数’ 接收地址,使用ctx.params获取参数值

<body>
    <button>点击发送get请求</button>
    <script>
        {
            //通过/get/3的方式进行传参,后台通过/get/:id进行获取,ctx.params得到具体参数值
            document.querySelector("button").onclick = function(){
                let xhr = new XMLHttpRequest();
                xhr.open("get","/getInfo/1");
                xhr.onload = function(){
                    console.log(xhr.responseText);//{"status":1,"msg":"请求成功"}
                }
                xhr.send();
            };
        }
    </script>
</body>

login.js:get请求(/get/id传参方式)

//get请求(/get/id传参方式)
router.get("getInfo","/getInfo/:id",ctx=>{
    console.log(ctx.params);//{ id: '1' }
    ctx.body = {
        status:1,
        msg:"请求成功"
    };
});

4.2post传参方式

post传参方式,如果需要发送数据,需要通过send(data)方法进行发送,发送给的数据是通过http正文头发送。

且post传参方式,node.js后台需要使用koa-body进行接收,ctx.request.body获取参数。

注意:如果post请求方式通过queryString方式传参,就需要通过ctx.query获取参数。

4.2.1post传参方式注意点

  • post一般不通过queryString进行传参,因为queryString传参有长度限制(服务器会限制),默认2048。
  • 发送数据时候需要设置http正文头格式:post传参是通过HTTP正文进行传参,正文传参必须设置编码格式。同form表单的默认编码格式    <form action="" enctype="application/x-www-form-urlencoded"></form>。form表单中可以省略,但是ajax请求时不能省略。
  • 需要手动设置正文头,setRequestHeader()的content-type为json且发送的数据通过JSON.stringtify()进行处理,传递过去的数据node才会以对象进行接收。如果没有设置也可以接收,但是需要通过queryString模块ctx.query进行处理,但是前端这样传递数据不好。

注意点:

  1. 发送数据时候需要设置http正文头格式;
  2. 获取头部信息:getAllResponseHeaders  或者是getResponseHeader ;

4.2.2post传参方式设置http正文头格式

发送数据时候需要设置http正文头格式:

xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");  //默认编码
xhr.setRequestHeader("Content-type","multipart/form-data");  //二进制编码,上传文件时使用
xhr.setRequestHeader("Content-type","application/json");  //json编码:传输数据也需要时JSON格式

示例:注意使用post请求时,后台必须使用koa-body模块,才能获取到参数

http正文头格式为默认编码时

<body>
    <button>点击发送post请求</button>
    <script>
        {
            //通过/get/3的方式进行传参,后台通过/get/:id进行获取,ctx.params得到具体参数值
            document.querySelector("button").onclick = function(){
                let xhr = new XMLHttpRequest();
                xhr.open("post","/getPostInfo");
                xhr.onload = function(){
                    console.log(xhr.responseText);//{"status":1,"msg":"请求成功"}
                }
                //设置正文请求头
                xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
                let data = "username=zs&age=20";
                xhr.send(data);
            };
        }
    </script>
</body>

http正文头格式设置为JSON时:如果正文头是JSON格式,则传输数据也需要是json格式,必须使用JSON.stringify()将数据转为json格式

 //正文请求头设置为json时,传输数据也需要是JSON格式
                xhr.setRequestHeader("content-type","application/json; charset=utf-8");
                let data = JSON.stringify({
                    username:'zs',
                    age:12
                });

后台获取post参数:需要引入koa-body,然后通过ctx.request.body接收参数 

注意:ctx.body是ctx.response.body的别名,而ctx.request.body是post的传参。

const koaBody = require("koa-body");
app.use(koaBody());
//post请求
router.post("/getPostInfo",ctx=>{
    console.log(ctx.request.body);//{ username: 'zs', age: '20' }
    
    ctx.body = {
        status:1,
        msg:"请求成功"
    };
});

4.2.3onload()方法中获取返还头部信息

getAllResponseHeaders()获取所有头部信息(某些属性有可能会获取不到,大部分都能获取)  或者是getResponseHeader("请求头属性") 获取某个头部信息

                xhr.onload = function(){
                    console.log(xhr.responseText);//{"status":1,"msg":"请求成功"}
                    //获取所有头部信息
                    console.log(xhr.getAllResponseHeaders());
                    //获取某个头部信息
                    console.log(xhr.getResponseHeader("content-type"));//application/json; charset=utf-8
                }

4.2.4完整案例

ajax_post.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <button>点击发送post请求</button>
    <script>
        {
            //通过/get/3的方式进行传参,后台通过/get/:id进行获取,ctx.params得到具体参数值
            document.querySelector("button").onclick = function(){
                let xhr = new XMLHttpRequest();
                xhr.open("post","/getPostInfo");
                xhr.onload = function(){
                    console.log(xhr.responseText);//{"status":1,"msg":"请求成功"}
                    //获取所有头部信息
                    console.log(xhr.getAllResponseHeaders());
                    //获取某个头部信息
                    console.log(xhr.getResponseHeader("content-type"));
                }
                //设置正文请求头
                // xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");//默认编码
                // xhr.setRequestHeader("content-type","multipart/form-data");//二进制编码,上传文件时使用
                // let data = "username=zs&age=20";
                //正文请求头设置为json时,传输数据也需要是JSON格式
                xhr.setRequestHeader("content-type","application/json; charset=utf-8");//json编码:传输数据也需要时JSON格式
                // 传输数据也需要是json格式,必须使用JSON.stringify()将数据转为json格式
                let data = JSON.stringify({
                    username:'zs',
                    age:12
                });
                xhr.send(data);
            };
        }
    </script>
</body>
</html>

login.js:

app.use(koaBody());
//post请求
router.post("/getPostInfo",ctx=>{
    console.log(ctx.request.body);//{ username: 'zs', age: '20' }
    
    ctx.body = {
        status:1,
        msg:"请求成功"
    };
});

 结果:所有头部信息

date: Wed, 18 Sep 2019 01:59:50 GMT
connection: keep-alive
content-length: 33
content-type: application/json; charset=utf-8

4.3同步及异步ajax

  • 设置异步的请求不会影响其他请求或代码的执行;
  • 当设置同步执行时,其后其他请求或代码必须等该请求执行完后,才会进行执行

异步:设置异步的请求不会影响其他请求或代码的执行

<body>
    <button>按钮一</button>
    <button>按钮二</button>
    <script>
    {
        let btns = document.querySelectorAll("button");
        btns[0].onclick = function(){
            let xhr = new XMLHttpRequest();
            xhr.open("get","/getInfo/2",true);
            xhr.onload = function(){
                console.log(xhr.responseText);
            }
            xhr.send();
        }
        //点击第二个按钮时进行打印
        btns[1].onclick = function(){
            console.log("按钮二打印。。。");
            
        }
    }
    </script>
</body>

结果:按钮一的请求不会影响按钮二的打印结果(测试时网速太快看不到效果,可以将Network中的online网络改为slow3G再测)

异步:当设置同步执行时,其他请求或代码必须等该请求执行完后,才会进行执行

 xhr.open("get","/getInfo/2",false);

 结果:永远都只会先打印按钮一发送的请求后再执行按钮二的请求

4.4onload()

以前是使用onreadystatechange后,通过readyState的状态判断是否请求完毕,现在使用onload()更加简洁方便。

onload()方法是异步的,即使写在send()方法前面也会再send()方法执行后才会执行,一般习惯上会将send()方法放在最后面。因为很多东西必须在send()之前设置才有用,如setRequestHeader()就必须在send()之前设置。

5.onreadystatechange——了解

5.1onreadystatechange

onreadystatechange:存有处理服务器响应的函数,每当 readyState 改变时,onreadystatechange 函数就会被执行

5.2readyState

readyState:存有服务器响应的状态信息。

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

5.3status常用状态码

status常用状态——http状态码
HTTP状态码描述

100

继续。继续响应剩余部分,进行提交请求

200

成功

301

永久移动。请求资源永久移动到新位置

302

临时移动。请求资源零时移动到新位置

304

未修改。请求资源对比上次未被修改,响应中不包含资源内容

401

未授权,需要身份验证

403

禁止。请求被拒绝

404

未找到,服务器未找到需要资源

500

服务器内部错误。服务器遇到错误,无法完成请求

503

服务器不可用。临时服务过载,无法处理请求

5.4onreadystatechange示例: 

<body>
    <button>点击</button>
    <script>
        document.querySelector("button").onclick = function(){
            let xhr = new XMLHttpRequest();
            xhr.open("get","/getInfo/3",true);
            xhr.onreadystatechange = function(){
                //判断服务求响应状态为4和返还状态200(成功)
                if(xhr.readyState == 4){
                    if(xhr.status == 200){
                        console.log(xhr.responseText);//{"status":1,"msg":"请求成功"}
                    }
                }
            }
            xhr.send();
        };
    </script>
</body>

5.5onload实现onreadystatechange功能

其实,使用onload也有服务器响应信息和返回状态码:建议使用onload会更加简洁

xhr.onload = function(){
                console.log(xhr.readyState);//4
                console.log(xhr.status);//200
                console.log(xhr.responseText);//{"status":1,"msg":"请求成功"}
            }

6.返还数据类型(XML,JSON) 

前端和后台之前,平台和平台之间数据传输都会使用同一的数据格式,现在主流的数据跨平台交互有XML和JSON。

6.1获取原始数据xhr.response

//获取原始数据
console.log(xhr.response);

6.2返还数据为json时xhr.responseText

  • 服务器返还json数据:xhr.responseText 来获取
xhr.responseText  //来获取

6.3返还数据为json时,xhr.responseXML来获取 

  • 服务器返还xml数据 :
  1. xhr.responseXML //获取值
  2. 服务器端设置response里的content-type内容ctx.set("content-type","text/xml");
  3. 前端重写XML(以防后台没有指定content-type类型):xhr.overrideMimeType('text/xml;charset=utf-8');注意属性之间不能有空格
  4. 前端和服务器端随便那边设置返还数据格式即可,不需要都设置
xhr.responseXML //获取值

 示例:

前端HTML:

<body>
    <button>点击获取XML数据</button>
    <script>
    {
        document.querySelector("button").onclick = function(){
            let xhr = new XMLHttpRequest();
            xhr.open("get","/getXMLInfo",true);
            //如果后台没有设置XML的content-type,前端就必须重写格式
            xhr.overrideMimeType('text/xml;charset=utf-8');
            xhr.onload = function(){
                //获取XML格式数据
                console.log(xhr.responseXML);
                console.log(xhr.responseXML.getElementsByTagName("name")[0]);
                //获取原始数据
                console.log(xhr.response);
                
            }
            xhr.send();
        }
    }
    </script>
</body>

后台:

//获取XML数据
router.get("/getXMLInfo",ctx=>{
    ctx.set("content-type","text/xml");
    //注意这里反引号和xml内容不能换行
    ctx.body = `<?xml version='1.0' encoding='utf-8' ?>
        <books>
            <nodejs>
                <name>nodeJS实战</name>
                <price>52.0元</price>
            </nodejs>
            <react>
                <name>react进阶</name>
                <price>56.0元</price>
            </react>
        </books>`;
});

 结果:

为防止后台没有写XML的content-type,需要在前端重写XML格式:

xhr.overrideMimeType('text/xml;charset=utf-8');

7.利用FormData对象来实现文件上传

7.1 创建FormData对象

注意点:

  1. <input type="file" class="myfile">通过files属性获取到的是类数组
  2. 通过new FormData()创建文件上传对象;
  3.  formData.append(name,value);name必须和后台接收时name保持一致,value可以是文件也可以是普通数据
  4. 文件上传必须通过正文方式进行传递,所以必须使用post请求
  5. 使用FormData时会自动对content-type进行设置,就不需要再进行手动设置
  6. 后台接收数据时,通过前端append()中的name属性即可获取到对应数据或文件
  7. 再通过fs模块对相应文件进行转存即可。ctx.request.files.img.path即文件的临时路径,对临时路径中的文件转存到服务器下路径即可
  8. 文件转存时有可能出现文件夹权限问题,需要手动开启权限。且文件夹不存在,需要先创建文件夹

示例:

前端:注意上传文件是通过正文提交,所以必须使用post方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <input type="file" class="myfile">
    <button>点击上传</button>
    <script>
        document.querySelector("button").onclick = function(){
            let myfile = document.querySelector(".myfile");
            //files属性返回的是类数组
            let files = myfile.files;
            
            //创建FormData对象,进行上传(使用FormData后,就不需要在表单中使用form-data进行上传)
            let formData = new FormData();
            //img表示name,相当于form表单中的name属性,file[0]表示要上传的单个文件
            formData.append("img",files[0]);
            //其他的数据,也可以进行传输
            formData.append("username","张三");

            //文件上传必须通过正文方式进行传递,所以必须使用post请求
            //使用FormData时会自动对content-type进行设置,就不需要再进行手动设置
            let xhr = new XMLHttpRequest();
            xhr.open("post","/upload",true);
            xhr.onload = function(){
                console.log(xhr.responseText);
            };
            // 没选择文件需要提示,否则会报错
            if(files>0){
                xhr.send(formData);
            }else{
                alert("请选择文件");
            }
        };
    </script>
</body>
</html>

后台:获取上传文件必须使用mutipart:ture;通过ctx.request.files.img获取文件

const Koa = require("koa");
const Router = require("koa-router");
const static = require("koa-static");
const koaBody = require("koa-body");
const fs = require("fs");

let app = new Koa();
let router = new Router();
app.use(static(__dirname + "/static"));
//上传文件时,必须设置允许文件上传,否则接收不了
app.use(koaBody({
    multipart:true
}));

//上传文件
router.post("/upload",ctx=>{
    //通过前端append()中的name属性即可获取到对应数据或文件
    // console.log(ctx.request.body);//{ username: '张三' }
    // console.log(ctx.request.files.img);
    //通过fs模块对相应文件进行转存即可
    //ctx.request.files.img.path即文件的临时路径,对临时路径中的文件转存到服务器下路径即可
    let fileData = fs.readFileSync(ctx.request.files.img.path);
    //文件转存时有可能出现文件夹权限问题,需要手动开启权限
    //判断文件夹不存在,需要先创建文件夹
    if(!fs.existsSync("static/imgs")){
        fs.mkdirSync("static/imgs/");
    }
    fs.writeFileSync("static/imgs/"+ctx.request.files.img.name,fileData);
    
    ctx.body = {
        status:1,
        msg:"文件上传成功"
    };
});

app.use(router.routes());
app.listen("8888");

 结果:{"status":1,"msg":"文件上传成功"}

7.2 监控上传进度——upload 事件

7.2.1upload事件下的各种事件——事件钩子

以下事件都是在upload事件下:

  • onloadstart   上传开始
  • onprogress  数据传输进行中(evt.total :需要传输的总大小;evt.loaded :当前上传的文件大小;
  • onabort 上传操作终止(取消上传xhr.abort())
  • onerror  上传失败
  • onload 上传成功
  • onloadend 上传完成(不论成功与否)

7.2.2监控文件上传进度示例

注意点:

  • 使用<process>标签可以显示文件上传进度
  • 监控文件上传速度(需要onloadstart和onprogress的时间差,及时间差内文件已上传的文件大小),当前文件大小/时间差 即文件上传速度;时间差需要转为单位为秒
  • evt.total :需要传输的总大小;evt.loaded :当前上传的文件大小
  • 需要处理上传的单位b/s ,判断文件足够大时使用kb/s;

文件上传页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
    .progressSpan{
        display: none;
        color: seagreen;
    }

    </style>
</head>
<body>
    <input type="file" class="myfile">
    进度:<progress value="0" max="100"></progress>&nbsp;&nbsp;<span class="progressSpan">10%</span>&nbsp;&nbsp;
    速度:<span class="speed">20b/s</span><br><br>
    <button>点击上传</button>
    <button>取消上传</button>
    <script>
    {
        let btns = document.querySelectorAll("button");
        let xhr = new XMLHttpRequest();
        btns[0].onclick = function(){
            let sTime = 0;//文件开始上传时间
            let eTime = 0;//文件开始上传时间
            let fileInitSize = 0;//文件开始上传大小
            xhr.open("post","/fileUpload",true);
            //获取上传文件
            let file = document.querySelector(".myfile").files[0];
            let formData = new FormData();
            formData.append("imgFile",file);

            //upload事件监控文件上传进度
            xhr.upload.onloadstart = function(){
                console.log("文件开始上传");
                sTime = new Date().getTime();
                fileInitSize = 0;
            };
            xhr.upload.onprogress = function(evt){
                console.log("文件上传中");
                //在onprogress事件中监控上传进度
                let progress = (evt.loaded / evt.total * 100).toFixed(0);
                //将进度进行显示
                document.querySelector("progress").value = progress;
                document.querySelector(".progressSpan").style.display = "inline-block";
                document.querySelector(".progressSpan").innerHTML = progress+"%";

                //监控文件上传速度(需要onloadstart和onprogress的时间差,及时间差内文件已上传的文件大小)
                eTime = new Date().getTime();
                //需要将时间差转为秒s
                let diffTime = (eTime-sTime)/1000;
                //各个进度文件上传的文件大小
                let curFileSize = evt.loaded;
                let diffFileSize = curFileSize - fileInitSize;
                //获取上传速度(需要处理上传的单位b/s kb/s)
                let speed = diffFileSize/diffTime;
                let unit = "";
                if(speed/1024>1){
                    speed = speed/1024;
                    unit = "b/s";
                }
                if(speed/1024>1){
                    speed = speed/1024;
                    unit = "kb/s";
                }
                document.querySelector(".speed").innerHTML = speed.toFixed(2)+unit;
                //使用当前文件大小/时间差 即文件上传速度
                sTime = eTime;
                fileInitSize = curFileSize
            };
            xhr.upload.onabort = function(){
                console.log("取消文件上传");
            };
            xhr.upload.onerror = function(){
                console.log("文件上传失败");
            };
            //上传成功
            xhr.upload.onload = function(){
                console.log(xhr.responseText);
            };
            xhr.upload.onloadend = function(){
                console.log("文件上传完成");
            };
            xhr.send(formData);
        };
        btns[1].onclick = function(){
            //取消文件上传方法
            xhr.abort();
        };
    }
    </script>
</body>
</html>

后台处理:

//监控文件上传进度
router.post("/fileUpload",(ctx,next)=>{
    //通过前端append()中的name属性即可获取到对应数据或文件
    //ctx.request.files.imgFile.path即文件的临时路径,对临时路径中的文件转存到服务器下路径即可
    let fileData = fs.readFileSync(ctx.request.files.imgFile.path);
    
    //判断文件夹不存在,需要先创建文件夹
    if(!fs.existsSync("static/imgs")){
        fs.mkdirSync("static/imgs/");
    }
    fs.writeFileSync("static/imgs/"+ctx.request.files.imgFile.name,fileData);
    
    ctx.body = {
        status:1,
        msg:"文件上传成功"
    };
});

 结果:

8.回顾

1.ajax基本使用:创建XMLHttpRequest对象,xhr.open(),xhr.onload,xhr.send()

2.get/post在ajax中的使用

3.ajax中成功的返还:onload

4.返还数据格式:response,responseText,responseXML

5.FormData对象:创建FormData对象,form.append(name,value)

6.upload事件对象:各个监控文件上传的事件方法

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值