網(wǎng)站運營優(yōu)化方案優(yōu)秀軟文營銷案例
ajax 封裝
- 一、 什么是Ajax?
- 二、 Ajax的優(yōu)缺點?
- 2.1 優(yōu)點
- 2.2 缺點
- 三、 Ajax的使用
- 3.1 狀態(tài)碼
- 3.2 xhr的基本使用
- 3.3 ajax原生封裝:
- 3.3.1 觸發(fā)GET請求:
- 3.3.2 調(diào)用POST請求:
- 四、Ajax的約束
一、 什么是Ajax?
Ajax(Asynchronous JavaScript And XML)是2005年新出現(xiàn)的技術(shù),它的出現(xiàn)是為了解決這樣一個場景:整個頁面中,只有一小部分的數(shù)據(jù)需要進行更新,按照傳統(tǒng)的前后端交互,我們需要向服務器請求該網(wǎng)頁的所有數(shù)據(jù),然后再在客戶端重新渲染,這無疑是非常低效的操作。因此,Ajax就可以做到只向服務器請求我們想要的那一小部分數(shù)據(jù),而不用請求全部數(shù)據(jù),進而在刷新整個頁面的前提下更新那部分的數(shù)據(jù)。
舉個例子,我們?nèi)ワ埖瓿燥?#xff0c;然后點了一桌子菜,后來發(fā)現(xiàn)其中有一道菜太咸了,因此我們只需要讓服務員端回去給廚師重新做這一道菜再拿回來就行了。
吃飯事件 | 數(shù)據(jù)更新 |
---|---|
我們 | 客戶端 |
菜品 | 頁面所有的數(shù)據(jù) |
服務員 | ajax對象 |
廚師 | 服務器 |
當我們發(fā)現(xiàn)有一道菜太咸了,不需要讓廚師把所有的菜重新做一遍,只要讓服務員拿這一道菜回去給廚師重做這一操作就相當于讓ajax對象向后端請求那一小部分數(shù)據(jù)再拿回來更新頁面而無需刷新整個頁面。
二、 Ajax的優(yōu)缺點?
當我們發(fā)現(xiàn)有一道菜太咸了,不需要讓廚師把所有的菜重新做一遍,只要讓服務員拿這一道菜回去給廚師重做這一操作就相當于讓ajax對象向后端請求那一小部分數(shù)據(jù)再拿回來更新頁面而無需刷新整個頁面。
2.1 優(yōu)點
- 瀏覽器默認支持(一般瀏覽器都是支持JavaScript的)
- 提高用戶體驗(不需要刷新整個頁面,而只需要局部刷新)
- 提高頁面的性能(只需要請求部分數(shù)據(jù),所以數(shù)據(jù)量就明顯下降了)
2.2 缺點
- 破壞了瀏覽器的前進和后退功能(Ajax不會改變網(wǎng)頁URL,因此不會在瀏覽器記錄前后頁面)
- 對搜索引擎的支持較弱(搜索引擎無法監(jiān)測到JS引起的數(shù)據(jù)變化)
三、 Ajax的使用
Ajax的基本流程:創(chuàng)建XHR對象 => 發(fā)送數(shù)據(jù) => 接收數(shù)據(jù)
3.1 狀態(tài)碼
既然Ajax涉及到前后端的數(shù)據(jù)交互,那么我們就先來簡單的看一下幾種類型的狀態(tài)碼,如下表:
狀態(tài)碼 | 含義 |
---|---|
100 ~ 199 | 連接含義 |
200 ~ 299 | 各種成功的請求 |
300 ~ 399 | 重定向 |
400 ~ 499 | 客戶端錯誤 |
500 ~ 599 | 服務端錯誤 |
3.2 xhr的基本使用
在使用xhr之前,我們要創(chuàng)建一個xhr的實例對象:
let xhr = new XMLHttpRequest()
然后再調(diào)用xhr對象上的 open() 方法,表示創(chuàng)建一個請求。
open()
方法接收三個參數(shù):
- 第一個參數(shù): 請求的類型(例如get 、post)
- 第二個參數(shù): 請求的URL
- 第三個參數(shù): 是否異步發(fā)送請求(默認為true)
// 創(chuàng)建了一個Ajax請求
xhr.open('get', 'example.php', 'true')
光調(diào)用了 open()
方法還不夠,它只是創(chuàng)建了一個請求,但還沒有發(fā)送請求,因此我們還要調(diào)用xhr對象上的另一個方法,即 send()
方法,表示將請求發(fā)送給目標URL
send()
方法接收一個參數(shù):
- 第一個參數(shù): 作為請求主體發(fā)送的數(shù)據(jù)(例如post請求攜帶的數(shù)據(jù))
// 我們上面創(chuàng)建的是get請求,因此send()方法無需傳參
xhr.send()
請求發(fā)送出去后,客戶端需要接收服務器響應回來的數(shù)據(jù),xhr對象中有一些屬性,它們存儲著服務端返回來的一些數(shù)據(jù)信息,如下表所示:
屬性名 | 含義 |
---|---|
response Text | 服務端返回的文本信息 |
responseXML | 服務端返回的XML DOM 文檔 |
status | HTTP 狀態(tài)碼 |
status Text | HTTP狀態(tài)碼說明 |
readyState | xhr對象的請求響應階段 |
既然我們要獲取服務端返回的數(shù)據(jù),我們就要知道服務端是何時返回數(shù)據(jù)的,這就可以通過上面表格中的 readyState 屬性來判斷了
readyState
屬性一共有5個值,分別表示不同的請求響應階段:
- 0: 還未創(chuàng)建請求,即未調(diào)用 open() 方法
- 1: 已調(diào)用 open() 方法,但未發(fā)送 send() 方法
- 2: 已調(diào)用send() 方法,但未接收到響應
- 3: 已接收到部分響應
- 4: 已接收到全部的響應
同時,xhr對象可以綁定一個 readystatechange 事件,每當 readyState 屬性發(fā)生改變,都會觸發(fā)該事件,因此,該事件在一次請求中會被多次觸發(fā)
xhr.onreadystatechange = function() {console.log('readyState屬性發(fā)生改變了')
}
所以,我們可以在 readystatechange
事件中判斷一下 readyState
屬性是否為 4,即是否已經(jīng)接收所有的響應,然后還可以再繼續(xù)判斷一下 status
屬性,看看狀態(tài)碼是否為 200,當上述都成立了,我們再去 responseText
屬性 或 responseXML
屬性中獲取響應數(shù)據(jù)
xhr.onreadystatechange = function() {// 判斷是否已接收所有響應if(xhr.readyState === 4) {// 判斷狀態(tài)碼是否為200if(xhr.status === 200) {console.log(xhr.responseText)}}
}
3.3 ajax原生封裝:
//封裝一個ajax請求
function ajax(options) {//創(chuàng)建XMLHttpRequest對象const xhr = new XMLHttpRequest()//初始化參數(shù)的內(nèi)容options = options || {}options.type = (options.type || 'GET').toUpperCase()options.dataType = options.dataType || 'json'// 處理參數(shù)let str = ''let params = options.data;for (let key in params) {str += key + '=' + params[key] + '&'}params = str.slice(0, str.length - 1)//發(fā)送請求if (options.type === 'GET') {xhr.open('GET', options.url + '?' + params, true)xhr.send(null)} else if (options.type === 'POST') {xhr.open('POST', options.url, true)// post 請求需要設置請求頭 模仿表單請求xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')xhr.send(params)}//接收請求xhr.onreadystatechange = function () {if (xhr.readyState === 4) {let status = xhr.statusif (status >= 200 && status < 300) {options.success && options.success(xhr.responseText, xhr.responseXML)} else {options.fail && options.fail(status)}}}
}
3.3.1 觸發(fā)GET請求:
上面也講解了Ajax請求的簡單應用,同時也是拿 get 請求來舉得例子,因此這里我就不多做說明,唯一要講的就是,get請求所攜帶的數(shù)據(jù)是明文的,大小只有4k左右,而且它是寫在URL的 ? 后面的,例如這樣 example.php?query=4&em=0,所以若是我們要在發(fā)送get請求時攜帶數(shù)據(jù),只需要在調(diào)用 open() 方法時,將數(shù)據(jù)寫在第二個參數(shù)的URL的 ? 后面即可
let btn = document.querySelector('.btn')
btn.addEventListener('click', function () {ajax({type: 'get',dataType: 'json',data: { uid: '64dcd451a2d7172b77c03768', aid: "64db6361c57b44a4c47712af" },url: 'http://localhost:3456/wyc/getUser',success: function (text, xml) {//請求成功后的回調(diào)函數(shù)console.log(JSON.parse(text))},fail: function (status) {請求失敗后的回調(diào)函數(shù)console.log(status)}})
})
接收結(jié)果:
3.3.2 調(diào)用POST請求:
發(fā)送post請求的過程幾乎和get請求一樣,唯一不一樣的是數(shù)據(jù)的傳遞。大家都知道post請求的數(shù)據(jù)是放在請求體中的,因此我們需要調(diào)用xhr對象上的 setRequestHeader() 方法來模仿表單提交時的內(nèi)容類型
該方法傳入的參數(shù)比較固定,代碼如下
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
然后我們上面也說過,send() 方法接收的一個參數(shù)是請求主體發(fā)送的數(shù)據(jù),所以我們的post請求要發(fā)送的數(shù)據(jù)就要作為該方法的參數(shù),代碼如下:
xhr.send('query=4&em=0')
完整post請求:
let btn = document.querySelector('.btn')
btn.addEventListener('click', function () {ajax({type: 'post',dataType: 'json',data: { uid: '64dcd451a2d7172b77c03768', aid: "64db6361c57b44a4c47712af" },url: 'http://localhost:3456/wyc/attention',success: function (text, xml) {//請求成功后的回調(diào)函數(shù)console.log(JSON.parse(text))},fail: function (status) {請求失敗后的回調(diào)函數(shù)console.log(status)}})
})
請求結(jié)果:
四、Ajax的約束
了解過同源策略以后,我們來看看如何讓Ajax不受同源策略的限制而成功發(fā)送請求。CORS
(跨域資源共享)要求我們在發(fā)送請求時自定義一個HTTP頭部與服務器進行溝通,我們只需要設置一個名為 Origin 的頭部,值為當前頁面的源信息(協(xié)議、域名、端口),例如 Origin : http://example.com
;然后服務器需要設置一個名為 Access-Control-Allow-Origin
的響應頭部,其值為允許跨域訪問的源信息,若服務器設置的 Access-Control-Allow-Origin
與我們設置的 Origin 相同,則表示服務器允許我們跨域請求其資源,或者服務器可以將 Access-Control-Allow-Origin
值設為 *,此時表示允許任何域向其發(fā)送請求并且不受同源策略的限制。