(function(window){
var initParam ={
timeout:0, //超时时间(单位:毫秒)
type:””, //请求类型(get、post…)
url:””, //请求接口
data:””, //请求参数(格式:json对象) 例子:{“name”:”gerry”,”age”:”88”}
async:true, //同|异步请求 (异步:true 同步:false)
dataType:’’, //返回值处理(可拓展) 目前只实现:JSON
isFormData:false, //是否为formData传输方式 ajax-level2方案 PS:因为使用formData数据传输,后台接口需要变化,数据取值将要在request的form对象中取值
successEvent:function(data){}, //请求成功处理事件
errorEvent:function(x,xx,xxx){}, //请求失败处理事件
timeoutEvent:function(){}, //请求超时处理事件
requestHeader:{} //报文头设置(可自定义报文头)
};
var tool = {
hasOwn: function(obj, key){
return Object.prototype.hasOwnProperty.call(obj, key)
},
//类型判断
is:(function checkType(){
var is ={
types : [“Array”, “Boolean”, “Date”, “Number”, “Object”, “RegExp”, “String”, “Window”, “HTMLDocument”]
};
for(var i = 0, c; c = is.types[i ++ ]; ){
is[c] = (function(type){
return function(obj){
var temp = Object.prototype.toString.call(obj) == “[object “ + type + “]”;
if (temp) temp = obj;
return temp;
}
})(c);
};
return is;
})(),
//获取对象的key
keys: function(obj){
if(Object.keys) return Object.keys(obj);
var keys = [];
for(var key in obj){
if(this.hasOwn(obj, key)) keys.push(key);
};
return keys
},
//each循环
each:function(obj,callback){
var keys = this.keys(obj);
if (this.is.Array(obj)&&[].forEach){ //判断是否为数组且支持新特性
obj.forEach(callback);
}else{
var i = 0, len = keys.length, key, item;
while( i < len ){
key = keys[i++];
item = obj[key];
callback.call(obj, item, key);
}
}
},
//合并对象,将第二个合并到第一个对象上
MergeObject:function(target,source){
if(Object.assign){
return Object.assign(target, source)
}
var targetKeys = this.keys(target),
sourceKeys = this.keys(source),
i = 0
var len = sourceKeys.length;
while( i < len ){
var key = sourceKeys[i++]
target[key] = source[key];
}
return target;
},
//创建xhr对象
createXhrObject:function(){
var xhr;
try{
// IE7 已经有了XMLHttpRequest对象
XMLHttpRequest?(xhr= new XMLHttpRequest()):(xhr= new ActiveXObject('Microsoft.XMLHTTP'));
}catch (e){
throw new Error('ajax:Could not create an XHR object.')
};
return xhr;
},
//ajax参数处理,可拓展
dealWithParam:function(ajaxSetting,that,xhr){
switch (ajaxSetting.type.toUpperCase()) {
case "GET":
var getParam = "?";
tool.each(ajaxSetting.data,function(item,index){
getParam +=(encodeURI(index)+"="+encodeURI(item)+"&")
});
//处理最后一位"&"符号,其实不处理也没事,强迫症犯了,尴尬
getParam =getParam.substr(0,getParam.length-1);
//打开请求
xhr.open(ajaxSetting.type.toUpperCase(), ajaxSetting.url+=getParam, ajaxSetting.async);
break;
case "POST":
//打开请求
xhr.open(ajaxSetting.type.toUpperCase(), ajaxSetting.url, ajaxSetting.async);
xhr.setRequestHeader("Accept","*/*"); //解决火狐浏览器默认要求后台发送xml类型返回值
/*
* 1、 判断浏览器是否支持level2的属性
* a、 支持。判断用户配置中是否设定使用formdata传输数据
* b、 不支持。默认使用level1的传统发过誓传输数据
* */
that.postParam = undefined;
if(!(window.FormData && ajaxSetting.isFormData)){
xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
var postParam ="";
tool.each(ajaxSetting.data,function(item,index){
postParam +=(index+"="+item+"&")
});
//处理最后一位"&"符号,其实不处理也没事,强迫症犯了,尴尬
postParam =postParam.substr(0,postParam.length-1);
that.postParam = postParam;
}
break;
};
return xhr;
},
//判断IE版本
// 如果不是IE,返回 true
// 若是IE,返回IE版本号
getIEVersion:function(){
return function() {
// 能进到这里来,说明一定是IE
if (window.VBArray) {
// 取出IE的版本
var mode = document.documentMode
// IE6、IE7 不支持documentMode,那就使用XMLHttpRequest,支持的就是IE7,否则就是IE6
// 至于支持documentMode的IE,则直接return
return mode ? mode : window.XMLHttpRequest ? 7 : 6
} else {
return NaN
}
}()
},
//切割大文件
cutFile:function(file,cutSize){
var count = file.size / cutSize | 0 ,fileArr = [];
for (var i= 0; i< count ; i++){
fileArr.push({
name:file.name+".part"+(i+1),
file:file.slice( cutSize * i , cutSize * ( i + 1 ))
});
};
fileArr.push({
name:file.name+".part"+(count+1),
file:file.slice(cutSize*count,file.size)
});
return fileArr;
},
//如果浏览器不支持Promise特性,将用简易的promise代替(IE11-都不支持ES6 Promise)
createPromise:function(){
var newPromise = function(fn){
var promise = this;
//状态机的状态
var PROMISESTATE = {
PENDING : 0 ,
FULFILLED : 1 ,
REJECTED : 2
};
//存储当前变量的回调函数和标记对象为promise
promise._fullCalll =[],promise._rejCall = [];promise._name = "promise";
//执行过程中的状态变化(初始化状态为默认状态)
var _state = PROMISESTATE.PENDING;
//回调函数的参数
var _value = undefined;
//状态变更
function setState(stateT,valueT){
var promise = this;
_state = stateT;
_value = valueT;
handleFun.call(promise); //传递作用域,并且执行回调函数
};
//根据状态处理回调
function handleFun(){
var promise = this,isThen;
if (_state === PROMISESTATE.FULFILLED &&
typeof promise._fullCalll[0] === 'function') {
isThen = promise._fullCalll[0](_value);
};
if (_state === PROMISESTATE.REJECTED &&
typeof promise._rejCall[0] === 'function') {
isThen = promise._rejCall[0](_value);
};
//对于是否可以继续进行then做判断
// 1. 不可then的,直接return结束(条件:无返回值、返回值不是promise对象的)
// 2. 对于可以then的,将then的回调进行处理,然后对象之间传递。
if (isThen === undefined || !(typeof isThen === 'object' && isThen._name === 'promise')) return;
promise._fullCalll.shift(); promise._rejCall.shift(); //清除当前对象使用过的对调
isThen._fullCalll =promise._fullCalll;isThen._rejCall = promise._rejCall; //将剩下的回调传递到下一个对象
};
//promimse入口
function doResolve(fn){
var promise = this;
fn(function(param) {
setState.call(promise,PROMISESTATE.FULFILLED,param);
}, function(reason) {
setState.call(promise,PROMISESTATE.REJECTED,reason);
});
};
//函数then,处理回调,返回对象保证链式调用
this.then = function(onFulfilled,onRejected) {
this._fullCalll.push(onFulfilled);
this._rejCall.push(onRejected);
return this;
}
doResolve.call(promise,fn);
};
window.Promise = newPromise;
},
};
var tempObj ={
//通用ajax
common:function(options){
//每次清空请求缓存,并重新合并对象
var ajaxSetting = {},sendData=null;tool.MergeObject(ajaxSetting,initParam);tool.MergeObject(ajaxSetting,options);
//创建xhr对象
var xhr = tool.createXhrObject();
//针对某些特定版本的mozillar浏览器的BUG进行修正
xhr.overrideMimeType?(xhr.overrideMimeType("text/javascript")):(null);
//针对IE8的xhr做处理 PS:ie8下的xhr无xhr.onload事件,所以这里做判断
xhr.onload===undefined?(xhr.xhr_ie8=true):(xhr.xhr_ie8=false);
//参数处理(get和post),包括xhr.open get:拼接好url再open post:先open,再设置其他参数
ajaxSetting.data === ""?(xhr.open(ajaxSetting.type.toUpperCase(), ajaxSetting.url, ajaxSetting.async)):(xhr = tool.dealWithParam(ajaxSetting,this,xhr));
//设置超时时间(只有异步请求才有超时时间)
ajaxSetting.async?(xhr.timeoutEvent = ajaxSetting.timeout):(null);
//设置http协议的头部
tool.each(ajaxSetting.requestHeader,function(item,index){xhr.setRequestHeader(index,item)});
//onload事件(IE8下没有该事件)
xhr.onload = function(e) {
if(this.status == 200||this.status == 304){
ajaxSetting.dataType.toUpperCase() == "JSON"?(ajaxSetting.successEvent(JSON.parse(xhr.responseText))):(ajaxSetting.successEvent(xhr.responseText));
}else{
/*
* 这边为了兼容IE8、9的问题,以及请求完成而造成的其他错误,比如404等
* 如果跨域请求在IE8、9下跨域失败不走onerror方法
* 其他支持了Level 2 的版本 直接走onerror
* */
ajaxSetting.errorEvent(e.currentTarget.status, e.currentTarget.statusText);
}
};
//xmlhttprequest每次变化一个状态所监控的事件(可拓展)
xhr.onreadystatechange = function(){
switch(xhr.readyState){
case 1://打开
//do something
break;
case 2://获取header
//do something
break;
case 3://请求
//do something
break;
case 4://完成
//在ie8下面,无xhr的onload事件,只能放在此处处理回调结果
xhr.xhr_ie8?((xhr.status == 200 || xhr.status == 304)?(ajaxSetting.dataType.toUpperCase() == "JSON"?(ajaxSetting.successEvent(JSON.parse(xhr.responseText))):(ajaxSetting.successEvent(xhr.responseText))):(null)):(null);
break;
};
};
//ontimeout超时事件
xhr.ontimeout = function(e){
ajaxSetting.timeoutEvent(999,e?(e.type):("timeoutEvent")); //IE8 没有e参数
xhr.abort(); //关闭请求
};
//错误事件,直接ajax失败,而不走onload事件
xhr.onerror = function(e){
ajaxSetting.errorEvent();
};
if(this.postParam){
(this.postParam)?(sendData = this.postParam):(sendData = null);
}else{
sendData = ajaxSetting.data;
}
//发送请求
xhr.send(sendData);
},
//异步get请求
get:function(url,data,successEvent,errorEvent,timeoutEvent){
var ajaxParam ={
type:"get",
url:url,
data:data,
async:true,
isFormData:false,
successEvent:successEvent,
errorEvent:errorEvent,
timeoutEvent:timeoutEvent
};
ajax.common(ajaxParam);
},
//异步post请求
post:function(url,data,successEvent,errorEvent,timeoutEvent){
var ajaxParam ={
type:"post",
url:url,
data:data,
async:true,
isFormData:false,
successEvent:successEvent,
errorEvent:errorEvent,
timeoutEvent:timeoutEvent
};
ajax.common(ajaxParam);
},
//异步post请求
postFormData:function(url,formData,successEvent,errorEvent,timeoutEvent){
var ajaxParam ={
type:"post",
url:url,
data:formData,
async:true,
isFormData:true,
successEvent:successEvent,
errorEvent:errorEvent,
timeoutEvent:timeoutEvent
};
ajax.common(ajaxParam);
},
//同步post请求
postSync:function(url,data,successEvent,errorEvent,timeoutEvent){
var ajaxParam ={
type:"post",
url:url,
data:data,
async:false,
isFormData:false,
successEvent:successEvent,
errorEvent:errorEvent,
timeoutEvent:timeoutEvent
};
ajax.common(ajaxParam);
},
//集成promise的ajax请求(默认设置post和get请求,如有其他需求,可自己拓展)
promiseAjax:function (url,data,type){
if (!window.Promise) tool.createPromise(); //保证浏览器的兼容性
return new Promise(function(resolve, reject){
if (type === undefined) ajax.post(url,data,resolve,reject);
else ajax.get(url,data,resolve,reject);
});
},
/*
* 长轮询的实现
* param: type 请求类型
* url 请求接口地址
* data 请求参数
* successEvent(data,this) 成功事件处理 如果得到正确数据,则让轮询停止,则在第二个回调参数设置stop属性就好
* timeFrequency 每隔多少时间发送一次请求
* errorEvent 错误事件
* timeoutEvent 超时处理
* */
longPolling:function(type,url,data,successEvent,timeFrequency,errorEvent,timeoutEvent){
var ajaxParam ={
type:type,
url:url,
data:data,
async:true,
isFormData:false,
successEvent:function(dateCall){
successEvent(dateCall,this);
if (!this.stop){
setTimeout(function(){
tempObj.longPolling(type,url,data,successEvent,timeFrequency,errorEvent,timeoutEvent);
},timeFrequency);
};
},
//如果走了error说明该接口有问题,没必要继续下去了
errorEvent:errorEvent,
timeoutEvent:function(){
timeoutEvent();
setTimeout(function(){
tempObj.longPolling(type,url,data,successEvent,timeFrequency,errorEvent,timeoutEvent)
},timeFrequency);
}
};
ajax.common(ajaxParam);
},
/*
* ajax上传文件 -- level2的新特性,请保证你的项目支持新的特性再使用
* url 文件上传地址
* fileSelector input=file 选择器
* size 文件限制大小
* fileType 文件限制类型 mime类型
* successEvent 上传成功处理
* errorEvent 上传失败处理
* timeoutEvent 超时处理
*
* return: status: 0 请选择文件
* 1 超出文件限制大小
* 2 非允许文件格式
* */
upload:function(url,fileSelector,size,fileType,successEvent,errorEvent,timeoutEvent){
var formdata = new FormData(),fileNode = document.querySelector(fileSelector),fileCount = fileNode.files.length,data={},result ={};
//以下为上传文件限制检查
if ( fileCount > 0 ){
tool.each(Array.prototype.slice.call(fileNode.files),function(value){
//检查文件大小
if (value.size > size){
result["status"] = 1;
result["errMsg"] = "超出文件限制大小";
}else{
if (fileType != "*"){
//检查文件格式.因为支持formdata,自然支持数组的indexof(h5)
if (fileType.indexOf(value.type)=== -1 ){
result["status"] = 2;
result["errMsg"] = "非允许文件格式";
}else{
formdata.append(value.name,value);
};
}else{
formdata.append(value.name,value);
}
};
});
}else{
result["status"] = 0;
result["errMsg"] = "请选择文件";
};
if (result.status !== undefined) return result; //如果有错误信息直接抛出去,结束运行
var ajaxParam ={
type:"post",
url:url,
data:formdata,
isFormData:true,
successEvent:successEvent,
errorEvent:errorEvent,
timeoutEvent:timeoutEvent
};
ajax.common(ajaxParam);
},
/*
* ajax大文件切割上传(支持单个文件) -- level2的新特性,请保证你的项目支持新的特性再使用
* url 文件上传地址
* fileSelector input=file 选择器
* cutSize 切割文件大小
* fileType 文件限制类型 mime类型
* successEvent 上传成功处理
* progressEvent 上传进度事件
* errorEvent 上传失败处理
* timeoutEvent 超时处理事件
*
* return: status: 0 请选择文件
* 1 非允许文件格式
* */
upload_big:function(url,fileSelector,cutSize,fileType,successEvent,progressEvent,errorEvent,timeoutEvent){
var file = document.querySelector(fileSelector).files,result ={};
//以下为上传文件限制检查
if (file.length === 1){
if (fileType != "*"){
if (fileType.indexOf(file.type)=== -1 ){
result["status"] = 1;
result["errMsg"] = "非允许文件格式";
}
}
}else{
result["status"] = 0;
result["errMsg"] = "请选择文件/只能上传一个文件";
};
if (result.status !== undefined) return result; //如果有错误信息直接抛出去,结束运行
//判断上传文件是否超过需要切割的大小
if (file[0].size > cutSize){
var fileArr = tool.cutFile(file[0],cutSize); //切割文件
cutFile_upload(fileArr);
}else{
return tempObj.upload(url,fileSelector,file[0].size,fileType,successEvent,errorEvent,timeoutEvent);
};
/*
* 切割文件上传,配合后台接口进行对接
* 传输参数:
* count -- 当前传输part的次数
* name -- 做过处理的文件名称
* file -- 上传的.part的切割文件
* isLast -- 是否为最后一次切割文件上传(默认值:"true" 字符串,只有最后一次才附加)
* */
function cutFile_upload(fileArr,count){
var formData = new FormData();
if (count == undefined){
count = 0;
formData.append("count",count);
formData.append("name",fileArr[0].name);
formData.append("file".name,fileArr[0].file);
}else{
if (count === fileArr.length-1){
formData.append("isLast","true")
};
formData.append("count",count);
formData.append("name",fileArr[count].name);
formData.append("file".name,fileArr[count].file);
};
var ajaxParam ={
type:"post",
url:url,
data:formData,
isFormData:true,
successEvent:function(data){
/*
* data 参数设置 需要后台接口配合
* 建议:如果后台成功保存.part文件,建议返回下次所需要的部分,比如当前发送count为0,则data返回下次为1。
* 如果保存不成功,则可false,或者返回错误信息,可在successEvent中处理
*
* */
progressEvent(count+1,fileArr.length); //上传进度事件,第一个参数:当前上传次数;第二个参数:总共文件数
var currCount = Number(data);
if (currCount){
if (currCount != fileArr.length){
cutFile_upload(fileArr,currCount);
};
};
successEvent(data); //成功处理事件
},
errorEvent:errorEvent,
timeoutEvent:timeoutEvent
};
ajax.common(ajaxParam);
}
}
};
var outputObj = function(){
//虽然在IE6、7上可以支持,但是最好升级你的浏览器,毕竟xp已经淘汰,面向未来吧,骚年,和我一起努力吧!!
if( tool.getIEVersion() < 7 ){
//实在不想说:lowB,升级你的浏览器吧
throw new Error ("Sorry,please upgrade your browser.(IE8+)");
}
return tempObj;
};
window.ajax = new outputObj();
})(this);