导言在开始之前先想一想ajax是怎样的流程首先打开一个连接发送数据返回结果我们要自定义的设置有哪些设置请求方式设置请求头设置返回数据格式返回成功后或失败后我们要做的功能有哪些数据校验统一数据的格式支持文件上传对于传入参数的容错处理经过以上思考基本结构大致成型数据校验数据格式的统一建立连接设置请求头设置返回数据格式发送数据返回成功或失败代码如下class AJAX { constructor({url = “",method = “GET”,data = {},async = true,success,error,resType = “",headers = {}}) { //集中管理传递过来的参数 this.option = {url,method,data,async,success,error,resType,headers}; this.xhr = new XMLHttpRequest(); this.start(); } start() { //数据校验 this.checkOption(); //数据格式的统一 this.initOption(); //建立连接 this.open(); //设置请求头 this.setHeaders(); //设置返回数据格式 this.setResponseType(); //发送数据 this.sendData() //返回成功或失败 this.responseData(); }; }接下来添加校验功能首先url不能是空然后请求头必须是字面量对象格式 {key:value}再有就是一些简单的警告代码如下checkOption() { let {url,async,resType,headers} = this.option; if (url === ‘’) { throw new Error(‘请求地址不能为空’); //打印错误信息,并停止当前进程 //Console.error(‘请求地址为空’); 也可以打印错误信息,但是不能停止当前进程 } if(typeof headers !== ‘object’){ throw new Error(‘设置请求头时请传入 {key:value,key:value…} 的格式’); } if(typeof resType !== ‘string’){ throw new Error(‘设置返回数据格式时请传入字符出串格式’); } if (typeof url !== ‘string’) { //输出警告信息 console.warn(‘当前请求地址不是字符串,现在将其尝试转换为字符串’); } if (async === false && resType != ‘’) { console.warn(‘如果设置了请求方式为同步,即使设置了返回数据格式也不会生效’); }};需要注意的是返回数据格式可以设置这几个值,之后会写一个详细的传参指南接下来是数据的处理首先我们需要保证请求格式,不管传入时是大写还是小写,在我们设置请求格式时要是全部大写还有就是url可能是数字的,需要转换成字符为了方便将 async不是布尔型的转成布尔型,这是什么概念,就是传参时 写数字 1 是异步 数字 0 是同步将需要发送的内容做一个处理initOption() { let {url,async,method} = this.option; //url不是字符串转换成字符串 if (typeof url !== ‘string’) { try { this.option.url = url.toString(); console.log(转换成功: "${this.option.url}"); } catch (error) { throw new Error(‘url 转换字符串失败’); } } //async不是布尔型转成布尔型 if(typeof async !==‘boolean’){ async == true ? this.option.async = true : this.option.async = false; } //将 post get 转换为大写 this.option.method = method.toUpperCase(); //post和get数据初始化 if(this.option.method != ‘FORMDATA’){// [1] let data = this.option.data; if(typeof data === ‘object’){//[2] if( this.option.method === ‘GET’){ let arr=[]; for(let name in data){ arr.push(${name}=${data[name]});//[3] } let strData=arr.join(’&’);//[4] this.option.data=?${strData};//[5] }else if( this.option.method === ‘POST’){ let formData = new FormData();//[6] for(let key in data){ formData.append(${key},${data[key]}); } this.option.data=formData; } }else if(typeof data === ‘string’ && this.option.method === ‘GET’){//[7] this.option.data=?${data}; } }};这里详细说说对需要发送数据的处理,按照序号来说判断它不是 formData ,也就是说是 GET 和 POST 时我们进行数据处理,是 formData 不进行处理,直接发送,这是为了能够实现文件上传功能判断它是不是 {key:vlue} 这种格式的,是的话解析或拼接,不是的话跳到 [7] 如果是字符串直接加到 url 后边[3] [4] [5] 这里是为了处理成 url?key=value$key=value 这种 url 传参的数据格式[6] 是新建了一个 FormData 对象,是 ajax2.0 里边的,它最主要的可以用 ajax 实现文件上传功能,在这里是为了代码简单打开连接经过之前的数据处理这里只需要判断下是 GET 还是其他方式(post formdata),然后选择对应的连接方式 open(){ let {method,url,async,data} = this.option; if(method === ‘GET’){ this.xhr.open(method,url+data,async); }else{ this.xhr.open(method,url,async); } }设置自定义请求头将传入的参数进行解析,然后设置自定义请求头代码如下setHeaders(){ let headers = this.option.headers; for(let key in headers){ this.xhr.setRequestHeader(${key.toString()},${headers[key].toString()}) } }设置返回数据格式、发送数据由于同步请求时不能设置返回数据格式,所以做下判断发送数据这里,在经过之前的数据处理后只有 GET 方式有所区别,其他两种没有区别(支持 GET POST 以及我自己定义的一种,更多请求方法可自行扩展)setResponseType() { if (this.option.async) { this.xhr.responseType = this.option.resType; }}sendData(){ if(this.option.method == ‘GET’){ this.xhr.send(); }else{ this.xhr.send(this.option.data); }}请求完成后的数据返回请求完成后会返回数据 判断 success 以及 error 是不是函数,是的话会将数据返回给 success 或者将错误信息返回给 errorresponseData(){ this.xhr.onload = ()=>{ if(this.xhr.status >= 200 && this.xhr.status < 300 || this.xhr.status === 304){ typeof this.option.success === ‘function’ && this.option.success(this.xhr.response); }else{ typeof this.option.error === ‘function’ && this.option.error(this.xhr.statusText); } }}在实现基本功能后,突然想到 jQuery 的 ajax 是会返回一个 promise 对象,可以同时使用回掉函数,或者使用 then 和 catch 来处理数据 因此修改了下传入参数,以及返回数据的处理传参时代码如下//add resolve rejectclass AJAX { constructor({url = “",method = “GET”,data = {},async = true,success,error,resType = “",headers = {},resolve,reject}) { this.option = {url,method,data,async,success,error,resType,headers,resolve,reject}; this.xhr = new XMLHttpRequest(); this.start(); }}返回数据时代码如下responseData(){ this.xhr.onload = ()=>{ if(this.xhr.status >= 200 && this.xhr.status < 300 || this.xhr.status === 304){ typeof this.option.success === ‘function’ && this.option.success(this.xhr.response); this.option.resolve(this.xhr.response);//add }else{ typeof this.option.error === ‘function’ && this.option.error(this.xhr.statusText); this.option.reject(this.xhr.statusText);//add } }}最终代码class AJAX { constructor({url = “",method = “GET”,data = {},async = true,success,error,resType = “",headers = {},resolve,reject}) { this.option = {url,method,data,async,success,error,resType,headers,resolve,reject}; this.xhr = new XMLHttpRequest(); this.start(); } start() { //数据校验 this.checkOption(); //数据格式的统一 this.initOption(); //建立连接 this.open(); //设置请求头 this.setHeaders(); //设置返回数据格式 this.setResponseType(); //发送数据 this.sendData() //返回成功或失败 this.responseData(); }; checkOption() { let {url,async,resType,headers} = this.option; if (url === ‘’) { throw new Error(‘请求地址不能为空’); //打印错误信息,并停止当前进程 //Console.error(‘请求地址为空’); 也可以打印错误信息,但是不能停止当前进程 } if(typeof headers !== ‘object’){ throw new Error(‘设置请求头时请传入 {key:value,key:value…} 的格式’); } if(typeof resType !== ‘string’){ throw new Error(‘设置返回数据格式时请传入字符出串格式’); } // "” 与设置为"text"相同, 是默认类型 (实际上是 DOMString) // “arraybuffer” 将接收到的数据类型视为一个包含二进制数据的 JavaScript ArrayBuffer // “blob” 将接收到的数据类型视为一个包含二进制数据的 Blob 对象 // “document” 将接收到的数据类型视为一个 HTML Document 或 XML XMLDocument ,这取决于接收到的数据的 MIME 类型 // “json” 将接收到的数据类型视为 JSON 解析得到的 // “text” 将接收到的数据类型视为包含在 DOMString 对象中的文本 if (typeof url !== ‘string’) { //输出警告信息 console.warn(‘当前请求地址不是字符串,现在将其尝试转换为字符串’); } if (async === false && resType != ‘’) { console.warn(‘如果设置了请求方式为同步,即使设置了返回数据格式也不会生效’); } }; initOption() { let {url,async,method} = this.option; //url不是字符串转换成字符串 if (typeof url !== ‘string’) { try { this.option.url = url.toString(); console.log(转换成功: "${this.option.url}"); } catch (error) { throw new Error(‘url 转换字符串失败’); } } //async不是布尔型转成布尔型 if(typeof async !==‘boolean’){ async == true ? this.option.async = true : this.option.async = false; } //将 post get 转换为大写 this.option.method = method.toUpperCase(); //post和get数据初始化 if(this.option.method != ‘FORMDATA’){ let data = this.option.data; if(typeof data === ‘object’){ if( this.option.method === ‘GET’){ let arr=[]; for(let name in data){ arr.push(${name}=${data[name]}); } let strData=arr.join(’&’); this.option.data=?${strData}; }else if( this.option.method === ‘POST’){ let formData = new FormData(); for(let key in data){ formData.append(${key},${data[key]}); } this.option.data=formData; } }else if(typeof data === ‘string’ && this.option.method === ‘GET’){ this.option.data=?${data}; } } }; open(){ let {method,url,async,data} = this.option; if(method === ‘GET’){ this.xhr.open(method,url+data,async); }else{ this.xhr.open(method,url,async); } } setHeaders(){ let headers = this.option.headers; for(let key in headers){ this.xhr.setRequestHeader(${key.toString()},${headers[key].toString()}) } } setResponseType() { if (this.option.async) { this.xhr.responseType = this.option.resType; } } sendData(){ if(this.option.method == ‘GET’){ this.xhr.send(); }else{ this.xhr.send(this.option.data); } } responseData(){ this.xhr.onload = ()=>{ if(this.xhr.status >= 200 && this.xhr.status < 300 || this.xhr.status === 304){ typeof this.option.success === ‘function’ && this.option.success(this.xhr.response); this.option.resolve(this.xhr.response); }else{ typeof this.option.error === ‘function’ && this.option.error(this.xhr.statusText); this.option.reject(this.xhr.statusText); } } } all(promises) { return Promise.all(promises); };}function ajax({url,method,data,async,success,error,resType,headers}){ return new Promise((resolve, reject) => { return new AJAX({url,method,data,async,success,error,resType,headers,resolve,reject}); });}使用时可以将代码复制粘贴到单独的 js 文件然后用 script 标签引入 也可以添加一行 export 代码将最后的 ajax 暴露出去 使用import 引入 具体使用方法用法ajax({ url:‘api/login’, method:‘post’,//支持 GET POST 和我自定义的 FORMDATA ,传入时不区分大小写 data = { name:“yhtx”, id:“1997” },//除了这种还支持字符串 “name=yhtx&id=1997”;以及 formData 数据,在传入formData 数据时请将 method 设置为 FORMDATA async = true,//可以使用数字 1 代替 true ,数字 0 代替 false success(res){ //可以使用回调的形式处理数据也可以使用 then },error(err){ //可以使用回调的形式处理错误也可以使用 catch }, resType = “”,//可以传入 "” “arraybuffer” “blob” “document” “json” “text” headers = { mycookie: “46afqwiocibQEIJfa498./&678” //使用对象的方式传参 }}).then((res)=>{ //可以使用 then 的形式处理数据也可以使用回调函数}).catch((err)=>{ //可以使用 catch 的形式处理数据也可以使用回调函数})
...