1 jsonp
1.1 script預(yù)解釋
- 基礎(chǔ)知識:
- 每一個script指的就是一個獨(dú)立的域甘邀,不同的script代表不同的域受啥;
- 兩個不同的域之間函數(shù)的調(diào)用注暗,必須使函數(shù)定義階段的域先引入季眷,然后函數(shù)調(diào)用的函數(shù)的域后引入冕臭;順序相反不能拿到數(shù)據(jù)腺晾;
//1. 函數(shù)定義階段的域先引入瓢棒,函數(shù)執(zhí)行階段的域后引入,此時執(zhí)行正確丘喻,彈出123脯宿; <body> <script> function fn() { alert(123); } </script> <script> fn(); </script> </body>
//2. 函數(shù)執(zhí)行階段的域先引入,函數(shù)定義階段的域后引入泉粉,此時執(zhí)行會報(bào)錯连霉,即:fn is not defined; <body> <script> fn(); </script> <script> function fn() { alert(123); } </script> </body>
1.2 jsonp原理
- jsonp原理體驗(yàn):
- jsonp的原理:通過一個script建立一個獨(dú)立的域嗡靡,這個域的請求地址為百度的一個服務(wù)器跺撼,通過wd的值來查找數(shù)據(jù),然后去將數(shù)據(jù)作為一個實(shí)參讨彼,傳入到cb后面的函數(shù)中歉井,執(zhí)行cb后面函數(shù)名的函數(shù);
- jsonp請求的實(shí)質(zhì)是獲取百度服務(wù)器中數(shù)據(jù)庫中的數(shù)據(jù)哈误,作為實(shí)參傳入到全局函數(shù)中哩至;獲取數(shù)據(jù)的方式:在百度所搜框中輸入文字后,在控制臺中的network中會生成數(shù)據(jù)蜜自,然后找到帶
su?wd=
的地址后菩貌,在新的頁面中打開,就會看到數(shù)據(jù)重荠;然后刪除沒用的地址數(shù)據(jù)箭阶;設(shè)置cb的值為全局函數(shù)名即可煎饼; - jsonp請求的三步:
- 定義一個有名字的全局函數(shù)僵缺,作為cd后面的函數(shù)名细卧;
- 在全局函數(shù)中設(shè)置形參看尼,獲取實(shí)參數(shù)據(jù)歪玲;
- 通過script發(fā)送請求:通過script來創(chuàng)建一個域载矿,src賦值中包括(url?參數(shù)&cb=函數(shù)名)惧盹,在域中絮记,執(zhí)行cb后面的函數(shù)鸣皂,給函數(shù)傳入一個實(shí)參數(shù)據(jù)抓谴;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>jsonp體驗(yàn)</title> </head> <body> <script> window["xhfd"]=function(data) { console.log(data); } </script> <!--請求步驟:在url這個請求地址中,通過wd后面的賦值來進(jìn)行查找寞缝,查找到的數(shù)據(jù)作為實(shí)參傳入到cb后面的函數(shù)中執(zhí)行--> <script src="https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=zhouxingchi&cb=xhfd"></script> </body> </html>
2 ajax封裝
- jQuery中ajax體驗(yàn)
- 注意:在百度服務(wù)器中搜索獲取地址后癌压,向一個函數(shù)中傳入實(shí)參數(shù)據(jù),執(zhí)行函數(shù)荆陆,必須設(shè)置jsonp參數(shù)為cb滩届,cb設(shè)置的函數(shù)名為默認(rèn)的jQuery...;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>jQuery中jsonp體驗(yàn)</title> </head> <body> <script src="jquery.js"></script> <script> //https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=zhouxingchi&cb=xxx //分析:問號之前的為請求地址;wd等號后為搜索的內(nèi)容被啼;cd后面為調(diào)用函數(shù)的函數(shù)名帜消; $.ajax({ url:"https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su",//請求地址棠枉;后臺接口 data:{"wd":"扶搖"},//前端傳給后臺的數(shù)據(jù),可有可無的泡挺; type:"get",//請求方式辈讶,post,get,jsonp可有可無,如果寫了jsonp娄猫,沒寫默認(rèn)的都是get贱除; dataType: "jsonp",//返回的數(shù)據(jù)類型,可有可無的媳溺,如果傳了月幌,拿到的數(shù)據(jù)就是josn對象,如果沒有悬蔽,拿到的是字符串 jsonp:"cb",//可有可無扯躺,沒有,默認(rèn)是callback蝎困;但在百度服務(wù)器中搜索必須設(shè)置為cb fnLoading:function(){//等待加載 console.log("數(shù)據(jù)正在加載中录语,請耐心等待"); }, complete:function(){//加載完成 console.log("數(shù)據(jù)請求結(jié)束") }, success:function(data){//數(shù)據(jù)請求成功 console.log(data); }, error:function (data) {//數(shù)據(jù)請求失敗 //數(shù)據(jù)請求失敗的處理; }, timeout:2000//請求超時难衰,可有可無钦无,沒傳默認(rèn)3000; }) </script> </body> </html>
- 封裝myAjax函數(shù)
- 參數(shù):ajax({url:xxx,data:xxx,type:xxx,dataType:xxx,jsonp:xxx,fnLoading:xxx,complete:xxx,success:xxx,error:xxx,timeout})逗栽;
- 思路:
- 獲取參數(shù)盖袭;
- 獲取數(shù)據(jù)的四步
- 創(chuàng)建一個xml對象:需注意的是IE6瀏覽器下不兼容,需要做兼容處理
- 打開地址
- 發(fā)送請求
- 通過switch來創(chuàng)建不同情況下的設(shè)置
- get請求:參數(shù)在地址中彼宠,在url?的后面鳄虱,以鍵值對的形式連接;
- post請求:參數(shù)在請求體中凭峡,地址url后面不跟參數(shù)拙已;
- jsonp請求:與get和post兩種形式不同,獨(dú)立設(shè)置
- jsonp請求的步驟
- 新建一個全局變量摧冀,作為函數(shù)名倍踪,注意函數(shù)名中不能存在小數(shù)點(diǎn);
- 創(chuàng)建一個全局函數(shù)索昂,函數(shù)中設(shè)置形參建车,用于獲取實(shí)參;
- 新建一個script標(biāo)簽椒惨,插入到body的最后面缤至,用于發(fā)送請求,其中src值的形式為:url?參數(shù)&cb=函數(shù)名
- 響應(yīng)請求
- 響應(yīng)請求前可以添加fnLoading函數(shù)康谆;
- 添加請求事件后判斷
xml.readyState===4
成立后领斥,代表請求成功嫉到,可以設(shè)置執(zhí)行complete函數(shù); - 通過正則校驗(yàn)xml.status的狀態(tài)碼是否為2xx
- 如果校驗(yàn)成功月洛,代表響應(yīng)成功何恶,執(zhí)行success函數(shù);執(zhí)行函數(shù)前嚼黔,判斷需要返回的類型导而,然后傳入響應(yīng)的實(shí)參給函數(shù);
- 如果校驗(yàn)失敗隔崎,則返回狀態(tài)碼給error函數(shù)今艺;
- 添加等待超時判斷
- 添加定時器,判斷在指定timeout時間內(nèi)爵卒,是否響應(yīng)成功虚缎,如果未成功,執(zhí)行定時器函數(shù)钓株,彈出信息实牡;
- 注:在定時器前面判斷是否為jsonp執(zhí)行,如果是的話轴合,阻斷程序執(zhí)行创坞,不執(zhí)行定時器;
- 注意:
- 使用時受葛,設(shè)置對象中的屬性data時题涨,用對象的形式設(shè)置;利用json2url函數(shù)总滩,將對象轉(zhuǎn)換為字符串格式為"key=val&key=val"形式纲堵;
- 封裝的get和post只能在本地獲取數(shù)據(jù),不能跨域獲热蛴妗席函;跨域獲取用jsonp請求;
- 代碼:
- 執(zhí)行代碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>封裝的ajax</title> </head> <body> <script src="JS/ajax.js"></script> <script> myAjax({ url:"https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su", data:{wd:"zhouxingchi"}, type:"jsonp", dataType:"json", jsonp:"cb",//此處必須設(shè)置jsonp為cb冈涧,才能使用 success:function (data) { console.log(data); } }); </script> </body> </html>
- 封裝JS代碼:
//參數(shù):ajax({url:xxx,data:xxx,type:xxx,dataType:xxx,jsonp:xxx,fnLoading:xxx,complete:xxx,success:xxx,error:xxx,timeout}) //將對象中的屬性名和屬性值轉(zhuǎn)化為key=val&key=val的形式 function json2url(obj) { //參數(shù):對象茂附,返回值:字符串 //思路:對象-數(shù)組-字符串 obj.t=Math.random();//避免緩存 var ary=[]; //遍歷對象 for(var attr in obj){ ary.push(attr+"="+obj[attr]); } return ary.join("&"); } function jsonParse(strJson) { return "JSON" in window?JSON.parse(strJson):eval("("+strJson+")"); } function myAjax(json) { json=json||{}; //如果json中請求地址url不存在 if(!json.url) return; //參數(shù)獲取 var url=json.url; //data屬性值為一個對象,對象中為參數(shù) var data=json.data||{}; var type=json.type||"get"; var jsonp=json.jsonp||"callback"; var timeout=json.timeout||3000; var timer=null; //四步: //1 創(chuàng)建一個xml對象 //每個類函數(shù)都是window的一個屬性督弓; if(window.XMLHttpRequest){ var xml=new XMLHttpRequest(); }else{//IE6兼容處理 var xml=new ActiveXObject("Microsoft.XMLHTTP"); } //2 打開地址营曼;3 發(fā)送請求 //get請求:參數(shù)在地址中,在url?的后面咽筋,以鍵值對的形式連接溶推; //post請求:參數(shù)在請求體中,地址url后面不跟參數(shù); switch(type.toLowerCase()){ case "get": xml.open("get",url+"?"+json2url(data),true); xml.send(null); break; case "post": xml.open("post",url,true); xml.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); xml.send(json2url(data)); break; case "jsonp": //新建一個全局函數(shù) var kbfd="jsonp_"+Math.random(); kbfd=kbfd.replace(".","");//函數(shù)名中不能存在小數(shù)點(diǎn)蒜危,所以需要替換 window[kbfd]=function (data) { json.success && json.success(data); //卸磨殺驢虱痕,干掉script document.body.removeChild(oS); //將oS賦值為null; oS=null; }; data[jsonp]=kbfd; //創(chuàng)建script標(biāo)簽,設(shè)置其src辐赞,通過script發(fā)送請求 var oS=document.createElement("script"); //script中src包含url?參數(shù)&cb=kbfd oS.src=url+"?"+json2url(data); //script必須插入到頁面的底部 document.body.appendChild(oS); break; } //響應(yīng)請求之前的準(zhǔn)備 json.fnLoading && json.fnLoading(); //4 響應(yīng)請求 xml.onreadystatechange=function () { if(xml.readyState===4){ //請求成功 json.complete && json.complete(); clearTimeout(timer); //判斷后臺響應(yīng)成功還是失敳壳獭; if(/^2\d{2}$/.test(xml.status)){//響應(yīng)成功 if(json.dataType==="json"){ json.success && json.success(jsonParse(xml.responseText)); }else{ json.success && json.success(xml.responseText); } }else{//響應(yīng)失敗 json.error && json.error(xml.status); } } }; if(type==="jsonp") return; //5 等待超時 timer=setTimeout(function () { alert("您的網(wǎng)絡(luò)不行啊"); xml.onreadystatechange=null; },timeout); }
- 知識點(diǎn)
- 類是window的屬性