目錄
4.1.1get傳參的兩種方式:queryString和/get/id
5.5onload實現onreadystatechange功能
6.3返還數據爲json時,xhr.responseXML來獲取
1.重點掌握及知識要點
## 重點掌握
- 理解ajax基本使用
- 會使用XMLHttpRequest對象實現數據交互
- 瞭解onreadystatechange服務器響應信息(狀態碼)
- 會使用FormData對象上傳文件
- 瞭解upload事件對象(XMLHttpRequest下的事件對象)
## 知識要點
- ajax使用
- XMLHttpRequest對象
- FormData對象
- upload 事件對象
2.登錄簡單回顧
- 提出ajax驗證用戶名需求;
- 驗證錯誤後,如果通過跳轉解決很麻煩;
- 各種跳轉用戶體驗差
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異步無刷新驗證用戶名
注意:
- 通過 XMLHttpRequest對象中open()方法發起請求。xhr.open("get","/checkUser?username="+this.value,true); //true表示異步發送請求,false同步發送請求,默認爲false,所以必須設置爲true。
- 通過 XMLHttpRequest對象中onload()方法獲取返還數據。注意返回數據是從XMLHttpRequest對象中獲得的,xhr.responseText(獲取json數據)和xhr.response(獲取原始數據),xhr.responseXML(獲取XML數據)都可以獲取返還數據
- 獲取到的數據是JSON格式的,需要將其轉爲對象。JSON.parse(xhr.responseText).msg
- 後臺接收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
- queryString,通過queryString傳參有長度限制,默認爲2048
- /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進行處理,但是前端這樣傳遞數據不好。
注意點:
- 發送數據時候需要設置http正文頭格式;
- 獲取頭部信息: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常用狀態碼
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數據 :
- xhr.responseXML //獲取值
- 服務器端設置response裏的content-type內容ctx.set("content-type","text/html");
- 前端重寫XML(以防後臺沒有指定content-type類型):xhr.overrideMimeType('text/xml;charset=utf-8');注意屬性之間不能有空格
- 前端和服務器端隨便那邊設置返還數據格式即可,不需要都設置
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對象
注意點:
- <input type="file" class="myfile">通過files屬性獲取到的是類數組;
- 通過new FormData()創建文件上傳對象;
- formData.append(name,value);name必須和後臺接收時name保持一致,value可以是文件也可以是普通數據
- 文件上傳必須通過正文方式進行傳遞,所以必須使用post請求;
- 使用FormData時會自動對content-type進行設置,就不需要再進行手動設置
- 後臺接收數據時,通過前端append()中的name屬性即可獲取到對應數據或文件
- 再通過fs模塊對相應文件進行轉存即可。ctx.request.files.img.path即文件的臨時路徑,對臨時路徑中的文件轉存到服務器下路徑即可
- 文件轉存時有可能出現文件夾權限問題,需要手動開啓權限。且文件夾不存在,需要先創建文件夾
示例:
前端:注意上傳文件是通過正文提交,所以必須使用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> <span class="progressSpan">10%</span>
速度:<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事件對象:各個監控文件上傳的事件方法