前言
在日常工作中,我們經(jīng)常使用Jquery的Ajax來獲取接口數(shù)據(jù)晶府。但是有的時(shí)候項(xiàng)目里面用不到Jquery,為了減少加載Jquery庫(kù)的時(shí)間。也不用負(fù)擔(dān)Jquery復(fù)雜的邏輯處理帶來的性能消耗,所以我打算封裝一個(gè)源生的Ajax函數(shù)
需求整理
一般來說前端與服務(wù)器的通信是使用XHR的,但是我希望封裝的函數(shù)能有跨域的功能劳殖。所以我把JSONP整合進(jìn)來了.
下面看主體功能圖
功能圖.png
輸入?yún)?shù)
首先必須要定義個(gè)AJAX函數(shù),并設(shè)置一些輸入?yún)?shù)
function ajax(options){
var url = options.url || "", //請(qǐng)求的鏈接
type = (options.type || "get").toLowerCase(), //請(qǐng)求的方法,默認(rèn)為get
data = options.data || null, //請(qǐng)求的數(shù)據(jù)
contentType = options.contentType || "", //請(qǐng)求頭
dataType = options.dataType || "jsonp",
//請(qǐng)求的類型要是jsonp他利用得get 問號(hào)后面是?callback = 執(zhí)行成功的方法 callback可以依照規(guī)矩修改
async = options.async === undefined && true, //是否異步阶冈,默認(rèn)為true.
timeOut = options.timeOut, //超時(shí)時(shí)間闷尿。
before = options.before || function(){}, //發(fā)送之前執(zhí)行的函數(shù)
error = options.error || function(){}, //錯(cuò)誤執(zhí)行的函數(shù)
success = options.success || function() {}; //請(qǐng)求成功的回調(diào)函數(shù)
}
參數(shù)表
參數(shù)表.jpg
調(diào)用
//var json = "name=garfield&age=18"; //字符串
var json ={"haha":[{"name":"張三"},{"age":"23"}]}; //大JSON包
ajax({
type:"post", //發(fā)送數(shù)據(jù)的類型
url:"index.php", //添加自己的接口鏈接
timeOut:5000, //過期時(shí)間
data:json, //發(fā)送的數(shù)據(jù)
before:function(){
console.log("發(fā)送成功") //發(fā)送之前要做的事情
},
success:function(str){ //接收到數(shù)據(jù)成功后
console.log(str);
},
error:function(status,statusText){ //如果出現(xiàn)錯(cuò)誤后塑径,第一個(gè)表示錯(cuò)誤的狀態(tài) 第二個(gè)表示錯(cuò)誤的原因
console.log(status+"||"+statusText);
}
})
PHP接收
<?php
header("content-type:text/html; charset=utf-8");
$name = $_POST["haha"]; //對(duì)應(yīng)的就是JSON的name
echo($name[0]["name"]);
?>
編碼
一般來說發(fā)送到后端的數(shù)據(jù)女坑,若是包括中文或者某些標(biāo)點(diǎn)符號(hào),就要對(duì)數(shù)據(jù)進(jìn)行編碼
- 如果data為字符串,通過&分割,對(duì)鍵名與鍵值分別編碼
- 如果data為對(duì)象,把鍵值轉(zhuǎn)化為字符串统舀,在進(jìn)行編碼
- 由于encodeURIComponent不對(duì)+編碼,所以只有使用replace方法手動(dòng)編碼
- 若是使用get方法或者JSONP,則數(shù)據(jù)是通過URL參數(shù)傳到后臺(tái)匆骗,所以手動(dòng)添加數(shù)據(jù)到URL
//編碼數(shù)據(jù)
function setData() {
//設(shè)置對(duì)象的遍碼
function setObjData(data, parentName) {
function encodeData(name, value, parentName) {
var items = [];
name = parentName === undefined ? name : parentName + "[" + name + "]";
if (typeof value === "object" && value !== null) {
items = items.concat(setObjData(value, name));
} else {
name = encodeURIComponent(name);
value = encodeURIComponent(value);
items.push(name + "=" + value);
}
return items;
}
var arr = [],value;
if (Object.prototype.toString.call(data) == '[object Array]') {
for (var i = 0, len = data.length; i < len; i++) {
value = data[i];
arr = arr.concat(encodeData( typeof value == "object"?i:"", value, parentName));
}
} else if (Object.prototype.toString.call(data) == '[object Object]') {
for (var key in data) {
value = data[key];
arr = arr.concat(encodeData(key, value, parentName));
}
}
return arr;
};
//設(shè)置字符串的遍碼,字符串的格式為:a=1&b=2;
function setStrData(data) {
var arr = data.split("&");
for (var i = 0, len = arr.length; i < len; i++) {
name = encodeURIComponent(arr[i].split("=")[0]);
value = encodeURIComponent(arr[i].split("=")[1]);
arr[i] = name + "=" + value;
}
return arr;
}
if (data) {
if (typeof data === "string") {
data = setStrData(data);
} else if (typeof data === "object") {
data = setObjData(data);
}
data = data.join("&").replace("/%20/g", "+");
//若是使用get方法或JSONP誉简,則手動(dòng)添加到URL中
if (type === "get" || dataType === "jsonp") {
url += url.indexOf("?") > -1 ? (url.indexOf("=") > -1 ? "&" + data : data) : "?" + data;
}
}
}
XMLHttpRequerst
- 創(chuàng)建XHR對(duì)象 碉就,并對(duì)IE進(jìn)行兼容性處理
- 調(diào)用XHR的open方法,設(shè)置請(qǐng)求的方法,請(qǐng)求的鏈接,是否異步
- 設(shè)置請(qǐng)求頭
- 添加監(jiān)聽,如果成功則返回success函數(shù)闷串,報(bào)錯(cuò)則執(zhí)行error函數(shù)
- 調(diào)用XHR的send方法,發(fā)送數(shù)據(jù)瓮钥。如果get方法,我們通過setData方法把數(shù)據(jù)添加到URL中了,這里data設(shè)置為null
// XHR
function createXHR() {
//由于IE6的XMLHttpRequest對(duì)象是通過MSXML庫(kù)中的一個(gè)ActiveX對(duì)象實(shí)現(xiàn)的烹吵。
//所以創(chuàng)建XHR對(duì)象碉熄,需要在這里做兼容處理。
function getXHR() {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else {
//遍歷IE中不同版本的ActiveX對(duì)象
var versions = ["Microsoft", "msxm3", "msxml2", "msxml1"];
for (var i = 0; i < versions.length; i++) {
try {
var version = versions[i] + ".XMLHTTP";
return new ActiveXObject(version);
} catch (e) {}
}
}
}
//創(chuàng)建對(duì)象肋拔。
xhr = getXHR();
xhr.open(type, url, async);
//設(shè)置請(qǐng)求頭
if (type === "post" && !contentType) {
//若是post提交锈津,則設(shè)置content-Type 為application/x-www-four-urlencoded
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
} else if (contentType) {
xhr.setRequestHeader("Content-Type", contentType);
}
//添加監(jiān)聽
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (timeOut !== undefined) {
//由于執(zhí)行abort()方法后,有可能觸發(fā)onreadystatechange事件凉蜂,
//所以設(shè)置一個(gè)timeout_bool標(biāo)識(shí)琼梆,來忽略中止觸發(fā)的事件性誉。
if (timeout_bool) {
return;
}
clearTimeout(timeout_flag);
}
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
success(xhr.responseText);
} else {
error(xhr.status, xhr.statusText);
}
}
};
//發(fā)送請(qǐng)求
xhr.send(type === "get" ? null : data);
setTime(); //請(qǐng)求超時(shí)
}
JSONP
- 創(chuàng)建script標(biāo)簽
- 設(shè)置回調(diào)函數(shù)名稱
- 監(jiān)聽回調(diào)函數(shù)
- 設(shè)置URL,并添加到文檔中
function createJsonp() {
var script = document.createElement("script"),
timeName = new Date().getTime() + Math.round(Math.random() * 1000),
callback = "JSONP_" + timeName;
window[callback] = function(data) {
clearTimeout(timeout_flag);
document.body.removeChild(script);
success(data);
}
script.src = url + (url.indexOf("?") > -1 ? "&" : "?") + "callback=" + callback;
script.type = "text/javascript";
document.body.appendChild(script);
setTime(callback, script);
}
超時(shí)請(qǐng)求
- 設(shè)置一個(gè)全局的定時(shí)器標(biāo)識(shí),用來在回調(diào)函數(shù)中清除定時(shí)器
- JSONP
- 傳入兩個(gè)參數(shù),一個(gè)是回調(diào)函數(shù)名,一個(gè)是script標(biāo)簽
- 超時(shí)以后茎杂,移除監(jiān)聽函數(shù),移除script標(biāo)簽
- XHR
- 超時(shí)之后,調(diào)用XHR的about方法,停止請(qǐng)求
- 由于執(zhí)行about()方法后,有可能觸發(fā)onreadystatechange事件错览,所以設(shè)置一個(gè)timeout_bool標(biāo)識(shí),來忽略終止觸發(fā)的事件.
//設(shè)置請(qǐng)求超時(shí)
function setTime(callback, script) {
if (timeOut !== undefined) {
timeout_flag = setTimeout(function() {
if (dataType === "jsonp") {
delete window[callback];
document.body.removeChild(script);
} else {
timeout_bool = true;
xhr && xhr.abort();
}
console.log("timeout");
}, timeOut);
}
}
全部代碼
/**
* Created by Administrator on 2017/4/12.
* 自己封裝了一個(gè)AJAX小類庫(kù)
*/
(function(window,undefined) {
function ajax(options) {
//編碼數(shù)據(jù)
function setData() {
//設(shè)置對(duì)象的遍碼
function setObjData(data, parentName) {
function encodeData(name, value, parentName) {
var items = [];
name = parentName === undefined ? name : parentName + "[" + name + "]";
if (typeof value === "object" && value !== null) {
items = items.concat(setObjData(value, name));
} else {
name = encodeURIComponent(name);
value = encodeURIComponent(value);
items.push(name + "=" + value);
}
return items;
}
var arr = [],value;
if (Object.prototype.toString.call(data) == '[object Array]') {
for (var i = 0, len = data.length; i < len; i++) {
value = data[i];
arr = arr.concat(encodeData( typeof value == "object"?i:"", value, parentName));
}
} else if (Object.prototype.toString.call(data) == '[object Object]') {
for (var key in data) {
value = data[key];
arr = arr.concat(encodeData(key, value, parentName));
}
}
return arr;
};
//設(shè)置字符串的遍碼,字符串的格式為:a=1&b=2;
function setStrData(data) {
var arr = data.split("&");
for (var i = 0, len = arr.length; i < len; i++) {
name = encodeURIComponent(arr[i].split("=")[0]);
value = encodeURIComponent(arr[i].split("=")[1]);
arr[i] = name + "=" + value;
}
return arr;
}
if (data) {
if (typeof data === "string") {
data = setStrData(data);
} else if (typeof data === "object") {
data = setObjData(data);
}
data = data.join("&").replace("/%20/g", "+");
//若是使用get方法或JSONP煌往,則手動(dòng)添加到URL中
if (type === "get" || dataType === "jsonp") {
url += url.indexOf("?") > -1 ? (url.indexOf("=") > -1 ? "&" + data : data) : "?" + data;
}
}
}
// JSONP
function createJsonp() {
var script = document.createElement("script"),
timeName = new Date().getTime() + Math.round(Math.random() * 1000),
callback = "JSONP_" + timeName;
window[callback] = function(data) {
clearTimeout(timeout_flag);
document.body.removeChild(script);
success(data);
}
script.src = url + (url.indexOf("?") > -1 ? "&" : "?") + "callback=" + callback;
script.type = "text/javascript";
document.body.appendChild(script);
setTime(callback, script);
}
//設(shè)置請(qǐng)求超時(shí)
function setTime(callback, script) {
if (timeOut !== undefined) {
timeout_flag = setTimeout(function() {
if (dataType === "jsonp") {
delete window[callback];
document.body.removeChild(script);
} else {
timeout_bool = true;
xhr && xhr.abort();
}
console.log("timeout");
}, timeOut);
}
}
// XHR
function createXHR() {
//由于IE6的XMLHttpRequest對(duì)象是通過MSXML庫(kù)中的一個(gè)ActiveX對(duì)象實(shí)現(xiàn)的蝗砾。
//所以創(chuàng)建XHR對(duì)象,需要在這里做兼容處理携冤。
function getXHR() {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else {
//遍歷IE中不同版本的ActiveX對(duì)象
var versions = ["Microsoft", "msxm3", "msxml2", "msxml1"];
for (var i = 0; i < versions.length; i++) {
try {
var version = versions[i] + ".XMLHTTP";
return new ActiveXObject(version);
} catch (e) {}
}
}
}
//創(chuàng)建對(duì)象悼粮。
xhr = getXHR();
xhr.open(type, url, async);
//設(shè)置請(qǐng)求頭
if (type === "post" && !contentType) {
//若是post提交,則設(shè)置content-Type 為application/x-www-four-urlencoded
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
} else if (contentType) {
xhr.setRequestHeader("Content-Type", contentType);
}
//添加監(jiān)聽
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (timeOut !== undefined) {
//由于執(zhí)行abort()方法后曾棕,有可能觸發(fā)onreadystatechange事件扣猫,
//所以設(shè)置一個(gè)timeout_bool標(biāo)識(shí),來忽略中止觸發(fā)的事件翘地。
if (timeout_bool) {
return;
}
clearTimeout(timeout_flag);
}
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
success(xhr.responseText);
} else {
error(xhr.status, xhr.statusText);
}
}
};
//發(fā)送請(qǐng)求
xhr.send(type === "get" ? null : data);
setTime(); //請(qǐng)求超時(shí)
}
var url = options.url || "", //請(qǐng)求的鏈接
type = (options.type || "get").toLowerCase(), //請(qǐng)求的方法,默認(rèn)為get
data = options.data || null, //請(qǐng)求的數(shù)據(jù)
contentType = options.contentType || "", //請(qǐng)求頭
dataType = options.dataType || "", //請(qǐng)求的類型
async = options.async === undefined ? true : options.async, //是否異步申尤,默認(rèn)為true.
timeOut = options.timeOut, //超時(shí)時(shí)間。
before = options.before || function() {}, //發(fā)送之前執(zhí)行的函數(shù)
error = options.error || function() {}, //錯(cuò)誤執(zhí)行的函數(shù)
success = options.success || function() {}; //請(qǐng)求成功的回調(diào)函數(shù)
var timeout_bool = false, //是否請(qǐng)求超時(shí)
timeout_flag = null, //超時(shí)標(biāo)識(shí)
xhr = null; //xhr對(duì)角
setData();
before();
if (dataType === "jsonp") {
createJsonp();
} else {
createXHR();
}
}
window.ajax = ajax;
})(window);