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