在写类库前 我们一定要理清楚我们写的类库,传递的参数代表什么意思
然后在封装的时候,首先考虑的就是兼容性的问题,整体的构思
我的整体的代码分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
});
}
})
})()