vlambda博客
学习文章列表

模仿JQuery封装ajax功能

  注:这是 2019.09.09 我在 CSDN 发布的一篇文章。


需求分析


  因为有时候想提高性能,只需要一个ajax函数,不想引入较大的jq文件,尝试过axios,可是get方法不支持多层嵌套的json,post方式后台接收方式似乎要变。。也许是我不太会用吧。。其实换个方式接收也没什么,只是习惯了JQ序列化参数。所以上网搜集了很多资料,同时也进一步了解了一点JQ。以下代码很多来自于网上,自己整合了一下。


封装代码

/** * @Description: 模仿jQuery封装简单的ajax功能。 * @Author: [email protected] **/
var Ajax = {};(function($) { function ajax(options) { var str; var xmlHttpRequest; var timer; if (window.XMLHttpRequest) { xmlHttpRequest = new XMLHttpRequest(); } else { xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP"); }
var source = { type: "GET", processData: true, contentType: "application/x-www-form-urlencoded" }; options = mergeObject(source, options); if (options.contentType.replace(/(^\s*)|(\s*$)/g, "") === "application/json") { options.processData = false; } xmlHttpRequest = mergeObject(xmlHttpRequest, options.xhrFields); if (options.type.toUpperCase() === "GET") { str = param(mergeObject(urlorQuerytoObject(options.url), options.data)); if (options.url.indexOf("?") !== -1) { options.url = options.url.substr(0, options.url.indexOf("?")); } xmlHttpRequest.open("GET", options.url + "?" + str, true); xmlHttpRequest.send(null); } else { xmlHttpRequest.open(options.type.toUpperCase(), options.url, true); xmlHttpRequest.setRequestHeader("Content-type", options.contentType); if (options.processData) { str = param(options.data); } else { str = options.data; } xmlHttpRequest.send(str); } xmlHttpRequest.onreadystatechange = function() { var textStatus = ""; if (xmlHttpRequest.readyState === 4) { clearInterval(timer); if ((xmlHttpRequest.status >= 200 && xmlHttpRequest.status < 300) || xmlHttpRequest.status === 304) { if (xmlHttpRequest.status === 304) { textStatus = "notmodified"; } else { textStatus = "success"; } try { // 如果是JSON格式,自动转换为JSON对象 options.success(JSON.parse(xmlHttpRequest.responseText), textStatus); } catch (e) { options.success(xmlHttpRequest.responseText, textStatus); } } else { textStatus = "error"; if (typeof options.error === "function") { options.error(xmlHttpRequest, textStatus); } } if (typeof options.complete === "function") { options.complete(xmlHttpRequest, textStatus); } } }; //判断是否超时 if (typeof options.timeout === "number") { timer = setTimeout(function() { if (typeof options.error === "function") { options.error(xmlHttpRequest, "timeout"); options.complete(xmlHttpRequest, "timeout"); } if (typeof options.complete === "function") { options.complete(xmlHttpRequest, "timeout"); } xmlHttpRequest.abort(); }, options.timeout); } }
// 合并对象 function mergeObject(target) { if (target == null) { throw new TypeError("Cannot convert undefined or null to object"); } target = Object(target); for (var index = 1; index < arguments.length; index++) { var source = arguments[index]; if (source != null) { for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } } return target; }
// 把url中的查询字符串转为对象,主要是想当方式为get时,用data对象的参数覆盖掉url中的参数 function urlorQuerytoObject(urlorQuery) { var queryArr = []; var urlSplit = urlorQuery.split("?"); queryArr[0] = urlSplit[0]; if (urlSplit[1]) { queryArr[0] = urlSplit[1]; } queryArr = queryArr[0].split("&"); var obj = {}; var i = 0; var temp; var key; var value; while (i < queryArr.length) { temp = queryArr[i].split("="); key = temp[0]; value = temp[1]; obj[key] = value; i++; } return obj; }
// 序列化参数 // 转载自 https://www.jianshu.com/p/0ca22d53feea function param(obj, traditional) { if (traditional === "undefined") { traditional = false; } var rbracket = /\[\]$/, op = Object.prototype, ap = Array.prototype, aeach = ap.forEach, ostring = op.toString;
function isFunction(it) { return ostring.call(it) === "[object Function]"; }
function isArray(it) { return ostring.call(it) === "[object Array]"; }
function isObject(it) { return ostring.call(it) === "[object Object]"; }
function buildParams(prefix, obj, traditional, add) { var name; if (isArray(obj)) { // Serialize array item. aeach.call(obj, function(v, i) { if (traditional || rbracket.test(prefix)) { // Treat each array item as a scalar. add(prefix, v); } else { // Item is non-scalar (array or object), encode its numeric index. buildParams( prefix + "[" + (typeof v === "object" && v != null ? i : "") + "]", v, traditional, add ); } }); } else if (!traditional && isObject(obj)) { // Serialize object item. for (name in obj) { buildParams(prefix + "[" + name + "]", obj[name], traditional, add); } } else { // Serialize scalar item. add(prefix, obj); } }
// Serialize an array of form elements or a set of // key/values into a query string function jollyparam(a, traditional) { var prefix, s = [], add = function(key, valueOrFunction) { // If value is a function, invoke it and use its return value var value = isFunction(valueOrFunction) ? valueOrFunction() : valueOrFunction; s[s.length] = encodeURIComponent(key) + "=" + encodeURIComponent(value == null ? "" : value); }; // If an array was passed in, assume that it is an array of form elements. if (isArray(a)) { // Serialize the form elements aeach.call(a, function(item) { add(item.name, item.value); }); } else { // If traditional, encode the "old" way (the way 1.3.2 or older // did it), otherwise encode params recursively. for (prefix in a) { buildParams(prefix, a[prefix], traditional, add); } } // Return the resulting serialization return s.join("&"); }
return jollyparam(obj, traditional); }
$ = { get: function(url, data, success) { return ajax({ url: url, data: data, success: success }); }, post: function(url, data, success) { return ajax({ type: "POST", url: url, data: data, success: success }); }, ajax: ajax, param: param, urlorQuerytoObject: urlorQuerytoObject, mergeObject: mergeObject };
// 满足 JQuery 的使用习惯 if (typeof window.$ === "undefined") { window.$ = $; }})(Ajax);


用法


  高度模仿JQ。

 
// get请求$.get("", {}, function(data) {});
// post请求$.post("", {}, function(data) {});
// 更完整的ajax$.ajax({ type: "post", // 非必须,默认 get url: "", data: { }, xhrFields: { // 非必须,自定义 XHR 对象属性 withCredentials: true }, processData: true, // 非必须,默认 true contentType: "application/x-www-form-urlencoded", // 非必须,默认 application/x-www-form-urlencoded success: function(responseData, textStatus) { // textStatus : "success"、"notmodified" }, // timeout: 1, // 非必须,超时毫秒数,如果设置了,超时且存在error函数则会调用 error: function(xhr, textStatus) { // 非必须 // textStatus: "error"、"timeout" }, complete: function(xhr, textStatus) { // 非必须,无论成败最后均调用 // textStatus: "success"、"notmodified"、"error"、"timeout" }});

注意事项


1. 如果 " $ " 符号不能使用,请用 " Ajax " 替代,这个变量名若仍有冲突,请修改源代码首尾两行。

2. 如果返回的是json格式的字符串,会自动将字符串转为json对象传给success函数参数,其他情况均为字符串。



  第一次发博客,经验不足,引用了许多别人的代码,只是这功能已经缠了我很多天了,今天终于相对完善了,如有不妥,还请多多指教!


        GitHub: https://github.com/kill370354/my-ajax-imitate-jq