在寫類庫前 我們一定要理清楚我們寫的類庫,傳遞的參數代表什麼意思
然後在封裝的時候,首先考慮的就是兼容性的問題,整體的構思
我的整體的代碼分3個模塊,
1:ajax核心模塊;
2:util幫助庫(用來解決兼容性問題)
3:鏈式寫法Promise(由於本人對鏈式寫法研究有限,故只能鏈式調用兩個)
在ajax核心模塊方面,主要是對ajax裏面傳遞進來的參數進行了統一處理
如是否走緩存,是否是get系的方法,發送的數據如何處理等,統一的都在ajax核心模塊裏面處理,然後再調用ajax的4部曲 完成數據交互
具體代碼及詳細註釋如下
/**
* Created by pengrongshu-pc on 2015/9/20.
*/
(function () {
if (this.$http)return;
this.$http = function (setting) {
if(!util.isObject(setting))return;
//設置默認值
var defaultOption={
type:'GET',//設置交互方式
url:'',
data:'',
cache:false,//默認不走緩存
async:true,//默認爲異步方式
username:undefined,
password:undefined,
header:{},//默認爲空 看用戶 需不需要設置頭信息
success:function(){},//AJAX請求成功就執行
error:function(){},//ajax請求失敗執行
beforeSend: function () {
},//在發送前執行
complete: function () {
},//完成就執行
contentType: 'application/x-www-form-urlencoded',//給form表格用的
mimeType: '',//一個mime類型用來覆蓋XHR的 MIME類型
statusCode: {},//狀態碼
timeout: 0,//規定響應完成的最大時間
context: window,//上下文
dataType: 'text'//傳進來的data是什麼數據格式的
},tempVal;
//遍歷默認值
util.traverse(defaultOption,function(key){
defaultOption[key]=setting[key]||defaultOption[key]
});
//獲取XHR
var deferred=new Deferred();
var xhr=util.getXhR();
//處理 傳遞進來的參數 所要對應的操作
//如果不走緩存 我就在url後面加個隨機數
//那麼 就要判斷url 有沒有問號
if(!defaultOption.cache){
defaultOption.url=util.hasQuestionMark(defaultOption.url,'_='+(Math.random() * 0xffffff | 0))
}
//處理data前 要處理指定方法是什麼類的get 或者post處理不同
var methodReg=/^(get|post|delete|put|head)$/igm;
//判斷處理進來的f方法是否合法、
if(!(methodReg.test(defaultOption.type))){
throw new Error('data Parameter error');
}
//不管是get系還是post系 都要轉成uri格式 只是放的位置不同 data前提要是對象
if(util.isObject(defaultOption.data)){
tempVal=[];
util.traverse(defaultOption.data,function(key,value){
tempVal.push(encodeURIComponent(key)+'='+encodeURIComponent(value));
});
//將data改變爲uri格式了
defaultOption.data=tempVal.join('&')
}
//判斷是不是get系
var getReg=/^(get|put)$/igm;
if(getReg.test(defaultOption.type.toLocaleLowerCase())){
//說明是get系 get系將 數據放置到url後面 xhr.send 是不需要傳遞參數的data就可以清理了
defaultOption.url=util.hasQuestionMark(defaultOption.url,defaultOption.data);
defaultOption.data=void 0;
}
//處理完參數 開始ajax核心
xhr.open(defaultOption.type,defaultOption.url,defaultOption.async,defaultOption.username,defaultOption.password);
/*這裏不懂跟後臺怎麼用*/
defaultOption.contentType && (defaultOption.header['content-type'] = defaultOption.contentType);
//自定義頭信息
util.traverse(defaultOption.header, function (key, value) {
xhr.setRequestHeader && xhr.setRequestHeader(key, value);
});
/*這裏不懂怎麼跟後臺用 結束*/
//改變this關鍵字
defaultOption.success=util.bind(defaultOption.success,defaultOption.context);
defaultOption.error=util.bind(defaultOption.error,defaultOption.context);
//成功失敗統一處理
var __suc = function (context, headers) {
defaultOption.success(context, headers);
defaultOption.complete(context, headers);
deferred.promise.onsuccess(context,headers);
};
var __err = function (status, headers) {
defaultOption.error(status, headers);
defaultOption.complete(status, headers);
deferred.promise.onerror(status,headers)
};
// 重寫mime類型
defaultOption.mimeType && xhr.overrideMimeType(defaultOption.mimeType);
// 開始ajax 處理
xhr.onreadystatechange=function(){
//readyState 分4個階段 =4即 ajax完成 只是說ajax流程走完了
if(xhr.readyState===4){
//獲取不同的狀態碼 不同的狀態碼 對應不同 的操作
//這個是我們用戶自己傳遞的方法
tempVal=defaultOption.statusCode[xhr.status];
util.isFunction(tempVal)&&tempVal();
//獲取後臺返回的數據
tempVal=xhr.responseText;
//再判斷成功與否
if(/^2\d{2}$/.test(xhr.status)){
//2開頭表示成功,再判斷返回的是否是一個json
if(defaultOption.dataType.toLocaleLowerCase()==='json'){
try{
tempVal=util.parse(tempVal);
}catch(err){
defaultOption.error(arguments);
}
}
//將獲取到的數據和頭信息 返回給成功函數 成功函數 裏面 怎麼做 是由我們自己決定的
__suc(tempVal,xhr.getAllResponseHeaders());
}
}
}
//ajax 請求是否超時判斷
if(defaultOption.timeout>500){
//最慢也要五百毫秒用
if('timeout'in xhr){
//判斷xhr 裏面有沒有 timeout屬性
xhr.timeout=defaultOption.timeout;
xhr.ontimeout=function(){
//超過規定的時間 不管有沒有完成 我們都報一個失敗回去
__err(arguments);//你想給失敗傳什麼就傳什麼
}
}else{
//沒有就是低版本瀏覽器
window.setTimeout(function(){
if(!xhr.readyState==4){
//強制結束ajax
xhr.abort();
//再報一個失敗回去
__err(arguments);
}
},defaultOption.timeout)
}
};
defaultOption.beforeSend(xhr);//在發送前執行,具體執行什麼操作 由我們自己決定
xhr.send(defaultOption.data);
//以上ajax 全部完成
//供鏈式寫法用
return deferred
}
util = {
parse:(function(){
if(window.JSON){
return function(text){
return JSON.parse(text);
}
}
return function(text){
return (new Function('return '+text))()
}
})(),
bind:function(fn,context){
//就是用來改變this關鍵字
if(Function.prototype.bind){
return fn.bind(context)
}else{
return function(){
fn.apply(context,arguments)
}
}
},
each: (function () {
if ([].forEach) {
//如果數組中存在 forEach則
//forEach是可以傳遞兩個參數的一個回調 一個爲回調的上下文
return function (list) {
[].forEach.call(list, arguments[1], arguments[2])
}
}
return function (list, callback) {
for (var i = 0; i < list.length; i++) {
callback.call(arguments[2], list[i], i, list)
}
}
})(),
isType: function (type) {
return function (obj) {
return Object.prototype.toString.call(obj) == '[object ' + type + ']';
}
},
//動態創建方法
init: function () {
util.each(['Array', 'Object', 'Function', 'String'], function (item) {
//現在util.isArray...就是一個方法了 方法的內容是 function(obj){ return Object.prototype.toString.call(obj) == '[Object ' + type+']';}
util['is' + item] = util.isType(item)
})
},
forIn: function (obj, callback) {
if (!util.isObject(obj))return;
for (var key in obj) {
if (!obj.hasOwnProperty(key))continue;
callback.call(null, key, obj[key])
}
},
traverse: function (obj) {
//可以傳隨意參數
if (util.isArray(obj)) {
//第一個參數 改變的是裏面所調用方法的指向
return util.each.apply(null, arguments);
}
if(util.isObject(obj)){
return util.forIn.apply(null,arguments);
}
},
getXhR:(function(){
var list = [function () {
return new XMLHttpRequest();
}, function () {
return new ActiveXObject('Microsoft.XMLHTTP');
}, function () {
return new ActiveXObject('MsXML2.XMLHTTP');
}, function () {
return new ActiveXObject('MsXML3.XMLHTTP');
}];
for(var i=0;i<list.length;){
try{
return list[i]
}catch(err){
continue;
}
}
})(),
hasQuestionMark:function(str,data){
var reg=/\?/igm;
var temp='';
if(reg.test(str)){
//有有問號
temp='&';
}else{
//沒有問號
temp='?';
}
//將拼接好的url返回
return str+temp+data;
}
}
//init執行了纔會動態創建那些方法
util.init();
//鏈式寫法
var Promise=function(){
this.onSuccess=this.onerror=new Function;//兩個都是一個空函數
this.isPromis=true;
}
Promise.prototype.success=function(fn){
if(util.isFunction(fn)){
this.onsuccess=fn;
}
}
Promise.prototype.error=function(fn){
if(util.isFunction(fn)){
this.onerror=fn;
}
}
var Deferred = function () {
this.promise = new Promise();
this.status = 'uninit';
};
Deferred.prototype.done = function (func) {
this.status = 'done';
this.promise.success(func);
return this;
};
Deferred.prototype.fail = function (func) {
this.status = 'fail';
this.promise.error(func);
return this;
};
util.each(['get', 'post', 'getScript'], function (item) {
$http[item] = function (url, data, callback, datatype) {
if (item == 'getScript') {
item = 'get';
var __callback = callback;
callback = function (data) {
(new Function(data))();
__callback(data)
}
}
return $http({
type: item,
url: url,
data: data,
success: callback,
dataType: datatype
});
}
})
})()