要實(shí)現(xiàn)的效果
定義options參數(shù)選項(xiàng)
itheima() 函數(shù)是我們自定義的 Ajax 函數(shù)羞海,它接收一個(gè)配置對(duì)象作為參數(shù),配置對(duì)象中可以配置如下屬性:
- method 請(qǐng)求的類(lèi)型
- url 請(qǐng)求的 URL 地址
- data 請(qǐng)求攜帶的數(shù)據(jù)
- success 請(qǐng)求成功之后的回調(diào)函數(shù)
處理data參數(shù)
需要把 data 對(duì)象曲管,轉(zhuǎn)化成查詢(xún)字符串的格式却邓,從而提交給服務(wù)器,因此提前定義 resolveData 函數(shù)如下:
/*** 處理 data 參數(shù)
* @param {data} 需要發(fā)送到服務(wù)器的數(shù)據(jù)
* @returns {string} 返回拼接好的查詢(xún)字符串 name=zs&age=10
*/
function resolveData(data) {
var arr = []
for (var k in data) {
var str = k + '=' + data[k]
arr.push(str)
}
return arr.join('&')
}
定義itheima函數(shù)
在 itheima() 函數(shù)中院水,需要?jiǎng)?chuàng)建 xhr 對(duì)象腊徙,并監(jiān)聽(tīng) onreadystatechange 事件:
function itheima(options) {
var xhr = new XMLHttpRequest()
// 把外界傳遞過(guò)來(lái)的參數(shù)對(duì)象,轉(zhuǎn)換為 查詢(xún)字符串
var qs = resolveData(options.data)
// 注冊(cè)監(jiān)聽(tīng)
xhr.onreadystatechange = function () {
// 注冊(cè)監(jiān)聽(tīng)
if (xhr.readyState === 4 && xhr.status === 200) {
// 把服務(wù)器的json字符串轉(zhuǎn)成js對(duì)象
var result = JSON.parse(xhr.responseText)
options.success(result)
}
}
}
判斷請(qǐng)求的類(lèi)型
不同的請(qǐng)求類(lèi)型檬某,對(duì)應(yīng) xhr 對(duì)象的不同操作撬腾,因此需要對(duì)請(qǐng)求類(lèi)型進(jìn)行 if … else … 的判斷:
if (options.method.toUpperCase() === 'GET') {
// 發(fā)起GET請(qǐng)求
xhr.open(options.method, options.url + '?' + qs)
xhr.send()
} else if (options.method.toUpperCase() === 'POST') {
// 發(fā)起POST請(qǐng)求
xhr.open(options.method, options.url)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xhr.send(qs)
}
XMLHttpRequest Level2的新特性
舊版XMLHttpRequest的缺點(diǎn)
- 只支持文本數(shù)據(jù)的傳輸,無(wú)法用來(lái)讀取和上傳文件
- 傳送和接收數(shù)據(jù)時(shí)恢恼,沒(méi)有進(jìn)度信息民傻,只能提示有沒(méi)有完成
XMLHttpRequest Level2的新功能
- 可以設(shè)置 HTTP 請(qǐng)求的時(shí)限
- 可以使用 FormData 對(duì)象管理表單數(shù)據(jù)
- 可以上傳文件
- 可以獲得數(shù)據(jù)傳輸?shù)倪M(jìn)度信息
設(shè)置HTTP請(qǐng)求時(shí)限
有時(shí),Ajax 操作很耗時(shí)场斑,而且無(wú)法預(yù)知要花多少時(shí)間漓踢。如果網(wǎng)速很慢,用戶(hù)可能要等很久漏隐。新版本的 XMLHttpRequest 對(duì)象喧半,增加了 timeout 屬性,可以設(shè)置 HTTP 請(qǐng)求的時(shí)限:
上面的語(yǔ)句青责,將最長(zhǎng)等待時(shí)間設(shè)為 3000 毫秒挺据。過(guò)了這個(gè)時(shí)限取具,就自動(dòng)停止HTTP請(qǐng)求。與之配套的還有一個(gè)timeout` 事件吴菠,用來(lái)指定回調(diào)函數(shù):
<script>
var xhr = new XMLHttpRequest()
// 設(shè)置 超時(shí)時(shí)間
xhr.timeout = 30
// 設(shè)置超時(shí)以后的處理函數(shù)
xhr.ontimeout = function () {
console.log('請(qǐng)求超時(shí)了者填!')
}
xhr.open('GET', 'http://www.liulongbin.top:3006/api/getbooks')
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText)
}
}
</script>
FormData對(duì)象管理表單數(shù)據(jù)
Ajax 操作往往用來(lái)提交表單數(shù)據(jù)。為了方便表單處理做葵,HTML5 新增了一個(gè) FormData 對(duì)象占哟,可以模擬表單操作:
// 1. 新建 FormData 對(duì)象
var fd = new FormData()
// 2. 為 FormData 添加表單項(xiàng)
fd.append('uname', 'zs')
fd.append('upwd', '123456')
// 3. 創(chuàng)建 XHR 對(duì)象
var xhr = new XMLHttpRequest()
// 4. 指定請(qǐng)求類(lèi)型與URL地址
xhr.open('POST', 'http://www.liulongbin.top:3006/api/formdata')
// 5. 直接提交 FormData 對(duì)象,這與提交網(wǎng)頁(yè)表單的效果酿矢,完全一樣
xhr.send(fd)
FormData對(duì)象管理表單數(shù)據(jù)
FormData對(duì)象也可以用來(lái)獲取網(wǎng)頁(yè)表單的值榨乎,示例代碼如下:
// 獲取表單元素
var form = document.querySelector('#form1')
// 監(jiān)聽(tīng)表單元素的 submit 事件
form.addEventListener('submit', function(e) {
e.preventDefault()
// 根據(jù) form 表單創(chuàng)建 FormData 對(duì)象,會(huì)自動(dòng)將表單數(shù)據(jù)填充到 FormData 對(duì)象中
var fd = new FormData(form)
var xhr = new XMLHttpRequest()
xhr.open('POST', 'http://www.liulongbin.top:3006/api/formdata')
xhr.send(fd)
xhr.onreadystatechange = function() {}
})
上傳文件
新版 XMLHttpRequest 對(duì)象瘫筐,不僅可以發(fā)送文本信息蜜暑,還可以上傳文件。
實(shí)現(xiàn)步驟:
① 定義 UI 結(jié)構(gòu)
② 驗(yàn)證是否選擇了文件
③ 向 FormData 中追加文件
④ 使用 xhr 發(fā)起上傳文件的請(qǐng)求
⑤ 監(jiān)聽(tīng) onreadystatechange 事件
定義UI結(jié)構(gòu)
<!-- 1. 文件選擇框 -->
<input type="file" id="file1" />
<!-- 2. 上傳按鈕 -->
<button id="btnUpload">上傳文件</button>
<br />
<!-- 3. 顯示上傳到服務(wù)器上的圖片 -->
<img src="" alt="" id="img" width="800" />
驗(yàn)證是否選擇了文件
// 1. 獲取上傳文件的按鈕
var btnUpload = document.querySelector('#btnUpload')
// 2. 為按鈕添加 click 事件監(jiān)聽(tīng)
btnUpload.addEventListener('click', function() {
// 3. 獲取到選擇的文件列表
var files = document.querySelector('#file1').files
if (files.length <= 0) {
return alert('請(qǐng)選擇要上傳的文件策肝!')
}
// ...后續(xù)業(yè)務(wù)邏輯
})
向FormData中追加文件
// 1. 創(chuàng)建 FormData 對(duì)象
var fd = new FormData()
// 2. 向 FormData 中追加文件
fd.append('avatar', files[0])
使用 xhr 發(fā)起上傳文件的請(qǐng)求
// 1. 創(chuàng)建 xhr 對(duì)象
var xhr = new XMLHttpRequest()
// 2. 調(diào)用 open 函數(shù)肛捍,指定請(qǐng)求類(lèi)型與URL地址。其中之众,請(qǐng)求類(lèi)型必須為 POST
xhr.open('POST', 'http://www.liulongbin.top:3006/api/upload/avatar')
// 3. 發(fā)起請(qǐng)求
xhr.send(fd)
監(jiān)聽(tīng)onreadystatechange事件
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var data = JSON.parse(xhr.responseText)
if (data.status === 200) { // 上傳文件成功
// 將服務(wù)器返回的圖片地址拙毫,設(shè)置為 <img> 標(biāo)簽的 src 屬性
document.querySelector('#img').src = 'http://www.liulongbin.top:3006' + data.url
} else { // 上傳文件失敗
console.log(data.message)
}
}
}
顯示文件上傳進(jìn)度
計(jì)算文件上傳進(jìn)度
新版本的 XMLHttpRequest 對(duì)象中,可以通過(guò)監(jiān)聽(tīng) xhr.upload.onprogress 事件棺禾,來(lái)獲取到文件的上傳進(jìn)度缀蹄。語(yǔ)法格式如下:
// 創(chuàng)建 XHR 對(duì)象
var xhr = new XMLHttpRequest()
// 監(jiān)聽(tīng) xhr.upload 的 onprogress 事件
xhr.upload.onprogress = function(e) {
// e.lengthComputable 是一個(gè)布爾值,表示當(dāng)前上傳的資源是否具有可計(jì)算的長(zhǎng)度
if (e.lengthComputable) {
// e.loaded 已傳輸?shù)淖止?jié)
// e.total 需傳輸?shù)目傋止?jié)
var percentComplete = Math.ceil((e.loaded / e.total) * 100)
}
}
導(dǎo)入需要的庫(kù)
<link rel="stylesheet" href="./lib/bootstrap.css" />
<script src="./lib/jquery.js"></script>
基于Bootstrap渲染進(jìn)度條
<!-- 進(jìn)度條 -->
<div class="progress" style="width: 500px; margin: 10px 0;">
<div class="progress-bar progress-bar-info progress-bar?striped active" id="percent" style="width: 0%">
0%
</div>
</div>
動(dòng)態(tài)設(shè)置到進(jìn)度條上
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
// 1. 計(jì)算出當(dāng)前上傳進(jìn)度的百分比
var percentComplete = Math.ceil((e.loaded / e.total) * 100)
$('#percent')
// 2. 設(shè)置進(jìn)度條的寬度
.attr('style', 'width:' + percentComplete + '%')
// 3. 顯示當(dāng)前的上傳進(jìn)度百分比
.html(percentComplete + '%')
}
}
監(jiān)聽(tīng)上傳完成的事件
xhr.upload.onload = function() {
$('#percent')
// 移除上傳中的類(lèi)樣式
.removeClass()
// 添加上傳完成的類(lèi)樣式
.addClass('progress-bar progress-bar-success')
}