ajax – xhr level2新特性 json等眾多內容
1.
今天的內容其實挺多的,我們慢慢來說。首先第一個是xhr的基本使用,什麼是xhr?
XMLHTTPRequest是瀏覽器提供的js對象,可以請求伺服器上的數據資源,包括我們前面一直用的jq裡面的三個請求資源的方法都是基於xhr來封裝的。
那麼首先我們看到xhr的get請求怎麼來實現
首先要創建xhr實例通過new來實現
然後調用open函數,裡面值為請求方式以及url
第三步調用send函數
第四步監聽onreadyStateChange事件在這個事件裡面要注意一下請求狀態和伺服器響應狀態的固定寫法,還有伺服器響應回的數據
<!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> </head> <body> <script> // 1.創建xhr對象 var xhr = new XMLHttpRequest() // 2.調用open函數 決定請求方式和url xhr.open('get', '//www.liulongbin.top:3006/api/getbooks') // 3.調用send函數 xhr.send() // 4.監聽事件 xhr.onreadystatechange = function() { // 4.1注意請求狀態和伺服器響應狀態固定寫法 if (xhr.readyState ==4 && xhr.status == 200) { // 4.2獲取相應的數據 console.log(xhr.response); } } </script> </body> </html>0.2 1
我們看到在監聽請求狀態變化事件里有一個readystate的屬性這個屬性表示ajax當前請求所處的狀態,其中0表示xhr對象以創建,但請求未調用open。1表示已調用open函數。2表示已調用send函數。3表示數據接收中。最後4表示一切請求完成
那麼xhr帶參的get請求怎麼來實現的呢?只需要在open函數的url裡面接一個查詢字元串即可
xhr.open(‘get’, ‘//www.ssfddaf.com/api?name=%df%fd%gf’)
那麼什麼是查詢字元串?
在url末尾加上?參數=值多個參數間用&來連接這就是查詢字元串,無論是jQuery的三個請求方式還是xhr指定的參數其本質都是在url後帶查詢字元串
這裡還要了解一個點url編碼與解碼
url中只允許出線英文不允許中文等其他語種,所以他就會把除英文外其他語種轉換為%開頭帶兩個字元的樣式來代替
編碼encodeURI(‘中文;) 解碼decodeURI(%的字元)三組%表示一個中文
2.
接下來我們看到xhr怎麼發起post請求
第一步創建對象
第二部open函數把請求方式改為post
第三步設置content-type 這是一個固定寫法
xhr.setRequestHeader(『content-type』, 『application/x-www-form-urlencoded』)
第四步調用send函數 post的參數在這裡添加以查詢字元串的方式添加進來
第五步監聽事件
<!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> </head> <body> <script> // 1.創建xhr對象 var xhr = new XMLHttpRequest() // 2.調用open函數 xhr.open('post', '//www.liulongbin.top:3006/api/addbook') // 3.設置cententtype xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded') // 4.調用send函數 xhr.send('bookname=水府傳&author=我') // 5.監聽事件 xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { console.log(xhr.responseText); } } </script> </body> </html>
3.
數據交換格式
即伺服器與客戶端之間進行數據傳輸與交換的格式,XML和JSON這兩種
XML我們用的比較少,它是可擴展標記語言,跟html很相似
JSON
什麼事json,就是js對象和數組的字元串表示法,其中本質還是一個字元串它是輕量級文本數據交換格式
它的結構為有兩種對象結構和數組結構
對象結構
『{key:value}』咋一看跟對象很相似,但是首先外面會有引號,其次鍵值是字元類型必須加雙引號
數組結構
【a,a】
要注意的是鍵值的雙引號,json中不能寫注釋,不能使用undefined和函數作為值
json和對象互轉
obj = JSON.parse(json)(反序列化)
json = JSON.stringify(obj)(序列化)
4.
封裝自己的ajax函數
①先封裝一個處理data對象為查詢字元串的函數
②封裝函數xhr
③判斷不同的請求類型達到不同的方式
這個總之記住一點就是xhr調用請求的總體步驟就沒得問題
// 1.先封裝函數處理傳進來的參數為查詢字元串 function revolveData(data) { var arr = [] for (var k in data) { arr[arr.length] = k + '=' + data[k] } var str = arr.join('&') return str } // console.log(revolveData({name : '張三', age : 19})); // 2。封裝主體函數 function ajaxMine(obj) { var xhr = new XMLHttpRequest() var str = revolveData(obj.data) xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { var res = JSON.parse(xhr.response) obj.success(res) } } // 3.判斷不同的請求,做到不同的操作 if (obj.method.toUpperCase() == 'GET') { xhr.open(obj.method, obj.url + '?' +str) xhr.send() } else if (obj.method.toUpperCase() == 'POST') { xhr.open(obj.method, obj.url) xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded') xhr.send(str) } }
驗證
<!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> </head> <body> <script src="./封裝自己的ajax函數.js"></script> <script> /* ajaxMine({ method : 'get', url : '//www.liulongbin.top:3006/api/getbooks', data : { id : 2 }, success : function(res) { console.log(res); } }) */ ajaxMine({ method : 'post', url : '//www.liulongbin.top:3006/api/addbook', data : { bookname : '收首飾', author : '東風似舊', publisher : '身法' }, success : function(res) { console.log(res); } }) </script> </body> </html>
5.
xhr level2新特性
在我們舊版的xhr缺點就是不支援文件上傳而且沒有進度資訊只有完沒完成
在我們新版xhr
支援文件上傳,有進度資訊,還可以設置http時限,還可使用formdata對象管理表單數據
接下來我會一一開始xhr這四個新特性
5.1
首先第一個設置Http時限,也就是在規定時間如果還沒有完成請求任務那麼這個請求就失敗了
xhr.timeout = 2000
與之對應的還有一個ontimeout的事件在超時後會做些什麼
<!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> </head> <body> <script> var xhr = new XMLHttpRequest() xhr.timeout = 50 xhr.ontimeout = function() { console.log('請求超時了'); } xhr.open('get', '//www.liulongbin.top:3006/api/getbooks') xhr.send() xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { console.log(xhr.responseText); } } </script> </body> </html>
5..2
formdata管理表單
因為我們ajax主要是用來提交表單數據的嘛,所以H5就新增了一個FormData對象用來模擬表單操作
①新建formdata對象
②為formdata添加表單項
③創建xhr
④用xhr完成請求
<!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> </head> <body> <script> // 1.創建FormData對象 var fd = new FormData() // 2.往裡面添加表單項 fd.append('uname', '王五') fd.append('age' , 29) // 3,創建xhr對象 var xhr = new XMLHttpRequest() // 4.使用xhr對象制定請求類型與地址 xhr.open('post', '//www.liulongbin.top:3006/api/formdata') // 5.直接提交,formdata對象,這與提交網頁表單的效果完全一樣 xhr.send(fd) // 6.驗證 xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { console.log(xhr.responsete); } } </script> </body> </html>
formdata還有一個用法,就是可以用來獲取表單的值
<!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> </head> <body> <form action=""> <input type="text" name="uname"> <input type="password" name="pwd"> <input type="submit" value="提交"> </form> <script> var form = document.querySelector('form') form.onsubmit = e => { e.preventDefault() var xhr = new XMLHttpRequest() var fd = new FormData(form) xhr.open('post', '//www.liulongbin.top:3006/api/formdata') xhr.send(fd) xhr.onreadystatechange = () => { if (xhr.readyState == 4 && xhr.status == 200) { console.log(xhr.responseText); } } } </script> </body> </html>
5.3
上傳文件
①定義UI結構
②驗證是否選擇了文件
③像formdata追加文件
④用xhr發起上傳請求
⑤監聽事件
<!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> </head> <body> <!-- 1.定義ui結構 --> <!-- 1.1文件選擇框 --> <input type="file"> <!-- 1.2上傳按鈕 --> <input type="submit" value="上傳文件"> <!-- 1.3img標籤 用來顯示上傳成功後的圖片 --> <img src="" alt=""> <script> // 2.驗證是否上傳了文件 var uploadBtn = document.querySelector('input:nth-of-type(2)') uploadBtn.addEventListener('click', function() { // 2.1注意這裡這個。files它是一個數組存放的是文件 let files = document.querySelector('input:first-child').files if (files.length > 0) { // 3.像formdata中追加文件 var fd = new FormData() // avator為頭像假裝這裡是上傳的頭像 fd.append('avatar', files[0]) // 4.使用xhr發起上傳文件請求 var xhr = new XMLHttpRequest() xhr.open('post', '//www.liulongbin.top:3006/api/upload/avatar') xhr.send(fd) // 5.監聽事件 xhr.onreadystatechange = () => { if (xhr.readyState == 4 && xhr.status == 200) { // console.log(xhr.responseText); let imgData = JSON.parse(xhr.responseText) if (imgData.status == 200) { document.querySelector('img').src = '//www.liulongbin.top:3006' + imgData.url } else { console.log('上傳文件失敗'); } } } } else { return alert('請上傳文件') } }) </script> </body> </html>
5.4
顯示上傳進度
通過xhr.upload.onprogress事件來監聽這裡面有三個屬性值得注意一下
<!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> </head> <body> <!-- 1.定義ui結構 --> <!-- 1.1文件選擇框 --> <input type="file"> <!-- 1.2上傳按鈕 --> <input type="submit" value="上傳文件"> <!-- 1.3img標籤 用來顯示上傳成功後的圖片 --> <img src="" alt=""> <script> // 2.驗證是否上傳了文件 var uploadBtn = document.querySelector('input:nth-of-type(2)') uploadBtn.addEventListener('click', function() { // 2.1注意這裡這個。files它是一個數組存放的是文件 let files = document.querySelector('input:first-child').files if (files.length > 0) { // 3.像formdata中追加文件 var fd = new FormData() // avator為頭像假裝這裡是上傳的頭像 fd.append('avatar', files[0]) // 4.使用xhr發起上傳文件請求 var xhr = new XMLHttpRequest() // -------------------------------- // 1.上傳進度監聽事件 xhr.upload.onprogress = e => { // 2.參數一 e.lengthComputable是一個布爾值,表示當前上傳的資源是否具有可計算的長度要有才能進去 if (e.lengthComputable) { // 參數二e.loaded已傳輸的位元組 // 參數三e.total需傳輸的總位元組 var percenComplete = Math.ceil((e.loaded / e.total) * 100) console.log(percenComplete); } } xhr.open('post', '//www.liulongbin.top:3006/api/upload/avatar') xhr.send(fd) // 5.監聽事件 xhr.onreadystatechange = () => { if (xhr.readyState == 4 && xhr.status == 200) { // console.log(xhr.responseText); let imgData = JSON.parse(xhr.responseText) if (imgData.status == 200) { document.querySelector('img').src = '//www.liulongbin.top:3006' + imgData.url } else { console.log('上傳文件失敗'); } } } } else { return alert('請上傳文件') } }) </script> </body> </html>
知道了上傳進度我們就可以通過bootstrap來一個進度條板的上傳進度
<!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="../day01/lib/bootstrap.css"> </head> <body> <!-- 1.定義ui結構 --> <!-- 1.1文件選擇框 --> <input type="file"> <!-- 1.2上傳按鈕 --> <input type="submit" value="上傳文件"> <!-- 1.3img標籤 用來顯示上傳成功後的圖片 --> <img src="" alt=""> <!-- 進度條 --> <div class="progress" style="width: 500px;"> <div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"> 0% </div> </div> <script> // 2.驗證是否上傳了文件 var uploadBtn = document.querySelector('input:nth-of-type(2)') uploadBtn.addEventListener('click', function() { // 2.1注意這裡這個。files它是一個數組存放的是文件 let files = document.querySelector('input:first-child').files if (files.length > 0) { // 3.像formdata中追加文件 var fd = new FormData() // avator為頭像假裝這裡是上傳的頭像 fd.append('avatar', files[0]) // 4.使用xhr發起上傳文件請求 var xhr = new XMLHttpRequest() // -------------------------------- // 1.監聽事件 var program = document.querySelector('.progress-bar') xhr.upload.onprogress = e => { // 2.參數一 e.lengthComputable是一個布爾值,表示當前上傳的資源是否具有可計算的長度要有才能進去 if (e.lengthComputable) { // 參數二e.loaded已傳輸的位元組 // 參數三e.total需傳輸的總位元組 var percenComplete = Math.ceil((e.loaded / e.total) * 100) // console.log(percenComplete); program.style.width = percenComplete + '%' program.innerText = '%' + percenComplete } } xhr.open('post', '//www.liulongbin.top:3006/api/upload/avatar') xhr.send(fd) // 5.監聽事件 xhr.onreadystatechange = () => { if (xhr.readyState == 4 && xhr.status == 200) { // console.log(xhr.responseText); let imgData = JSON.parse(xhr.responseText) if (imgData.status == 200) { document.querySelector('img').src = '//www.liulongbin.top:3006' + imgData.url } else { console.log('上傳文件失敗'); } } } } else { return alert('請上傳文件') } }) </script> </body> </html>
最後完善上傳成功的進度條
<!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="../day01/lib/bootstrap.css"> </head> <body> <!-- 1.定義ui結構 --> <!-- 1.1文件選擇框 --> <input type="file"> <!-- 1.2上傳按鈕 --> <input type="submit" value="上傳文件"> <!-- 1.3img標籤 用來顯示上傳成功後的圖片 --> <img src="" alt=""> <!-- 進度條 --> <div class="progress" style="width: 500px;"> <div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"> 0% </div> </div> <script> // 2.驗證是否上傳了文件 var uploadBtn = document.querySelector('input:nth-of-type(2)') uploadBtn.addEventListener('click', function() { // 2.1注意這裡這個。files它是一個數組存放的是文件 let files = document.querySelector('input:first-child').files if (files.length > 0) { // 3.像formdata中追加文件 var fd = new FormData() // avator為頭像假裝這裡是上傳的頭像 fd.append('avatar', files[0]) // 4.使用xhr發起上傳文件請求 var xhr = new XMLHttpRequest() // -------------------------------- // 1.監聽事件 var program = document.querySelector('.progress-bar') xhr.upload.onprogress = e => { // 2.參數一 e.lengthComputable是一個布爾值,表示當前上傳的資源是否具有可計算的長度要有才能進去 if (e.lengthComputable) { // 參數二e.loaded已傳輸的位元組 // 參數三e.total需傳輸的總位元組 var percenComplete = Math.ceil((e.loaded / e.total) * 100) // console.log(percenComplete); program.style.width = percenComplete + '%' program.innerText = '%' + percenComplete } } // ----------------------------------- // 2.上傳成功進度條變化 xhr.upload.onload = () => { program.className = '' program.className = 'progress-bar progress-bar-success' } xhr.open('post', '//www.liulongbin.top:3006/api/upload/avatar') xhr.send(fd) // 5.監聽事件 xhr.onreadystatechange = () => { if (xhr.readyState == 4 && xhr.status == 200) { // console.log(xhr.responseText); let imgData = JSON.parse(xhr.responseText) if (imgData.status == 200) { document.querySelector('img').src = '//www.liulongbin.top:3006' + imgData.url } else { console.log('上傳文件失敗'); } } } } else { return alert('請上傳文件') } }) </script> </body> </html>
6.
jQuery高級用法
用jq來實現文件上傳
①定義ui結構和前面一樣
②驗證是否選擇文件
③向formdata追加文件
④使用jq發起上傳請求
⑤jq實現loading效果 兩個方法一檢測到任何ajax開始或失敗就會調用
<!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> </head> <body> <!-- 1.定義UI結構 --> <form action=""> <input type="file" name="file" id=""> </form> <!-- 這裡出現了一點小問題 我在後面列印res始終列印不出來而且反正就想數據被清了一下思來想去才知道是我把button放在表單里了所以一點擊就會造成默認行為 --> <button type="submit">上傳圖片</button> <img style="display: none;" src="../../../../HTML/04-階段四 前後端交互/第四階段:前後端交互階段資料新/ajax課程資料/day3(7-12小節)/code/images/loading.gif" alt=""> <script src="../day01/lib/jquery.js"></script> <script> // 5.這個方法是偵聽到所有的ajax請求就會開始執行 $(document).ajaxStart(function() { $('img').show() }) $(document).ajaxStop(function() { $('img').hide() }) // 2.驗證是否選擇了文件 $('button').on('click', function() { // 這裡需要將jq對象轉為原生dom對象來使用files這個屬性 var files = $('input')[0].files // console.log(files); if (files.length <= 0) { return alert('請選擇文件') } else { // 3.向formdata追加文件 var fd = new FormData() fd.append('avatar', files[0]) // 4.利用jq來發起上傳請求 $.ajax({ method: 'POST', url: '//www.liulongbin.top:3006/api/upload/avatar', data: fd, processData: false, contentType: false, success: function (res) { console.log(res) } }) } }) </script> </body> </html>
7.
axios
今天的最後一個內容,什麼事axios,專註於網路數據請求的庫,相比於原生xhr更簡單易用,相比於jq更輕量化
<!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> <script src="./axios.js"></script> </head> <body> <button>發起get請求</button> <script> var btn = document.querySelector('button') /* btn.onclick = function() { var url = '//www.liulongbin.top:3006/api/get' var obj = {name : '張三', age : 29} axios.get(url, {params: obj}).then(function(res) { console.log(res); }) } */ btn.onclick = () => { axios({ method : 'get', url : '//www.liulongbin.top:3006/api/get', params : {name : '張三', age : 29} }).then(res => console.log(res)) } </script> </body> </html>
<!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> <script src="./axios.js"></script> </head> <body> <button>發起post請求</button> <script> /* document.querySelector('button').onclick =function() { var url = '//www.liulongbin.top:3006/api/post' var obj = {location : '重慶', address : '江北'} axios.post(url, {obj}).then(res => console.log(res)) } */ document.querySelector('button').onclick = () => { axios({ method : 'post', url : '//www.liulongbin.top:3006/api/post', data : {name : '張三', age : 29} }).then(res => console.log(res)) } </script> </body> </html>