Js之AJAX

前言


在日常工作中,我們經(jīng)常使用Jquery的Ajax來獲取接口數(shù)據(jù)晶府。但是有的時(shí)候項(xiàng)目里面用不到Jquery,為了減少加載Jquery庫(kù)的時(shí)間。也不用負(fù)擔(dān)Jquery復(fù)雜的邏輯處理帶來的性能消耗,所以我打算封裝一個(gè)源生的Ajax函數(shù)

需求整理


一般來說前端與服務(wù)器的通信是使用XHR的,但是我希望封裝的函數(shù)能有跨域的功能劳殖。所以我把JSONP整合進(jìn)來了.
下面看主體功能圖

功能圖.png

輸入?yún)?shù)


首先必須要定義個(gè)AJAX函數(shù),并設(shè)置一些輸入?yún)?shù)

function ajax(options){
 var url = options.url || "", //請(qǐng)求的鏈接
        type = (options.type || "get").toLowerCase(), //請(qǐng)求的方法,默認(rèn)為get
        data = options.data || null, //請(qǐng)求的數(shù)據(jù)
        contentType = options.contentType || "", //請(qǐng)求頭
        dataType = options.dataType || "jsonp", 
       //請(qǐng)求的類型要是jsonp他利用得get 問號(hào)后面是?callback = 執(zhí)行成功的方法 callback可以依照規(guī)矩修改
        async = options.async === undefined && true, //是否異步阶冈,默認(rèn)為true.
        timeOut = options.timeOut, //超時(shí)時(shí)間闷尿。 
        before = options.before || function(){}, //發(fā)送之前執(zhí)行的函數(shù)
        error = options.error || function(){}, //錯(cuò)誤執(zhí)行的函數(shù)
        success = options.success || function() {}; //請(qǐng)求成功的回調(diào)函數(shù)
}
參數(shù)表

參數(shù)表.jpg

調(diào)用


     //var json = "name=garfield&age=18";  //字符串
     var json ={"haha":[{"name":"張三"},{"age":"23"}]};  //大JSON包
  ajax({
    type:"post",  //發(fā)送數(shù)據(jù)的類型
    url:"index.php", //添加自己的接口鏈接
    timeOut:5000,  //過期時(shí)間
    data:json,     //發(fā)送的數(shù)據(jù)
    before:function(){
        console.log("發(fā)送成功")     //發(fā)送之前要做的事情 
    },
    success:function(str){        //接收到數(shù)據(jù)成功后
       console.log(str);
    },
    error:function(status,statusText){   //如果出現(xiàn)錯(cuò)誤后塑径,第一個(gè)表示錯(cuò)誤的狀態(tài) 第二個(gè)表示錯(cuò)誤的原因
      console.log(status+"||"+statusText);
    }
  }) 

PHP接收


<?php
  header("content-type:text/html; charset=utf-8");
  $name = $_POST["haha"];  //對(duì)應(yīng)的就是JSON的name
  echo($name[0]["name"]);
?>

編碼


一般來說發(fā)送到后端的數(shù)據(jù)女坑,若是包括中文或者某些標(biāo)點(diǎn)符號(hào),就要對(duì)數(shù)據(jù)進(jìn)行編碼

  • 如果data為字符串,通過&分割,對(duì)鍵名與鍵值分別編碼
  • 如果data為對(duì)象,把鍵值轉(zhuǎn)化為字符串统舀,在進(jìn)行編碼
  • 由于encodeURIComponent不對(duì)+編碼,所以只有使用replace方法手動(dòng)編碼
  • 若是使用get方法或者JSONP,則數(shù)據(jù)是通過URL參數(shù)傳到后臺(tái)匆骗,所以手動(dòng)添加數(shù)據(jù)到URL
  //編碼數(shù)據(jù)
        function setData() {
            //設(shè)置對(duì)象的遍碼
            function setObjData(data, parentName) {
                function encodeData(name, value, parentName) {
                    var items = [];
                    name = parentName === undefined ? name : parentName + "[" + name + "]";
                    if (typeof value === "object" && value !== null) {
                        items = items.concat(setObjData(value, name));
                    } else {
                        name = encodeURIComponent(name);
                        value = encodeURIComponent(value);
                        items.push(name + "=" + value);
                    }
                    return items;
                }
                var arr = [],value;
                if (Object.prototype.toString.call(data) == '[object Array]') {
                    for (var i = 0, len = data.length; i < len; i++) {
                        value = data[i];
                        arr = arr.concat(encodeData( typeof value == "object"?i:"", value, parentName));
                    }
                } else if (Object.prototype.toString.call(data) == '[object Object]') {
                    for (var key in data) {
                        value = data[key];
                        arr = arr.concat(encodeData(key, value, parentName));
                    }
                }
                return arr;
            };
            //設(shè)置字符串的遍碼,字符串的格式為:a=1&b=2;
            function setStrData(data) {
                var arr = data.split("&");
                for (var i = 0, len = arr.length; i < len; i++) {
                    name = encodeURIComponent(arr[i].split("=")[0]);
                    value = encodeURIComponent(arr[i].split("=")[1]);
                    arr[i] = name + "=" + value;
                }
                return arr;
            }

            if (data) {
                if (typeof data === "string") {
                    data = setStrData(data);
                } else if (typeof data === "object") {
                    data = setObjData(data);
                }
                data = data.join("&").replace("/%20/g", "+");
                //若是使用get方法或JSONP誉简,則手動(dòng)添加到URL中
                if (type === "get" || dataType === "jsonp") {
                    url += url.indexOf("?") > -1 ? (url.indexOf("=") > -1 ? "&" + data : data) : "?" + data;
                }
            }
        }

XMLHttpRequerst


  • 創(chuàng)建XHR對(duì)象 碉就,并對(duì)IE進(jìn)行兼容性處理
  • 調(diào)用XHR的open方法,設(shè)置請(qǐng)求的方法,請(qǐng)求的鏈接,是否異步
  • 設(shè)置請(qǐng)求頭
  • 添加監(jiān)聽,如果成功則返回success函數(shù)闷串,報(bào)錯(cuò)則執(zhí)行error函數(shù)
  • 調(diào)用XHR的send方法,發(fā)送數(shù)據(jù)瓮钥。如果get方法,我們通過setData方法把數(shù)據(jù)添加到URL中了,這里data設(shè)置為null
  // XHR
        function createXHR() {
            //由于IE6的XMLHttpRequest對(duì)象是通過MSXML庫(kù)中的一個(gè)ActiveX對(duì)象實(shí)現(xiàn)的烹吵。
            //所以創(chuàng)建XHR對(duì)象碉熄,需要在這里做兼容處理。
            function getXHR() {
                if (window.XMLHttpRequest) {
                    return new XMLHttpRequest();
                } else {
                    //遍歷IE中不同版本的ActiveX對(duì)象
                    var versions = ["Microsoft", "msxm3", "msxml2", "msxml1"];
                    for (var i = 0; i < versions.length; i++) {
                        try {
                            var version = versions[i] + ".XMLHTTP";
                            return new ActiveXObject(version);
                        } catch (e) {}
                    }
                }
            }
            //創(chuàng)建對(duì)象肋拔。
            xhr = getXHR();
            xhr.open(type, url, async);
            //設(shè)置請(qǐng)求頭
            if (type === "post" && !contentType) {
                //若是post提交锈津,則設(shè)置content-Type 為application/x-www-four-urlencoded
                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            } else if (contentType) {
                xhr.setRequestHeader("Content-Type", contentType);
            }
            //添加監(jiān)聽
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4) {
                    if (timeOut !== undefined) {
                        //由于執(zhí)行abort()方法后,有可能觸發(fā)onreadystatechange事件凉蜂,
                        //所以設(shè)置一個(gè)timeout_bool標(biāo)識(shí)琼梆,來忽略中止觸發(fā)的事件性誉。
                        if (timeout_bool) {
                            return;
                        }
                        clearTimeout(timeout_flag);
                    }
                    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {

                        success(xhr.responseText);
                    } else {
                        error(xhr.status, xhr.statusText);
                    }
                }
            };
            //發(fā)送請(qǐng)求
            xhr.send(type === "get" ? null : data);
            setTime(); //請(qǐng)求超時(shí)
        }

JSONP


  • 創(chuàng)建script標(biāo)簽
  • 設(shè)置回調(diào)函數(shù)名稱
  • 監(jiān)聽回調(diào)函數(shù)
  • 設(shè)置URL,并添加到文檔中
        function createJsonp() {
            var script = document.createElement("script"),
                timeName = new Date().getTime() + Math.round(Math.random() * 1000),
                callback = "JSONP_" + timeName;

            window[callback] = function(data) {
                clearTimeout(timeout_flag);
                document.body.removeChild(script);
                success(data);
            }
            script.src = url + (url.indexOf("?") > -1 ? "&" : "?") + "callback=" + callback;
            script.type = "text/javascript";
            document.body.appendChild(script);
            setTime(callback, script);
        }

超時(shí)請(qǐng)求

  • 設(shè)置一個(gè)全局的定時(shí)器標(biāo)識(shí),用來在回調(diào)函數(shù)中清除定時(shí)器
  • JSONP
    • 傳入兩個(gè)參數(shù),一個(gè)是回調(diào)函數(shù)名,一個(gè)是script標(biāo)簽
    • 超時(shí)以后茎杂,移除監(jiān)聽函數(shù),移除script標(biāo)簽
  • XHR
    • 超時(shí)之后,調(diào)用XHR的about方法,停止請(qǐng)求
    • 由于執(zhí)行about()方法后,有可能觸發(fā)onreadystatechange事件错览,所以設(shè)置一個(gè)timeout_bool標(biāo)識(shí),來忽略終止觸發(fā)的事件.
        //設(shè)置請(qǐng)求超時(shí)
        function setTime(callback, script) {
            if (timeOut !== undefined) {
                timeout_flag = setTimeout(function() {
                    if (dataType === "jsonp") {
                        delete window[callback];
                        document.body.removeChild(script);

                    } else {
                        timeout_bool = true;
                        xhr && xhr.abort();
                    }
                    console.log("timeout");

                }, timeOut);
            }
        }

全部代碼


/**
 * Created by Administrator on 2017/4/12.
 * 自己封裝了一個(gè)AJAX小類庫(kù)
 */
(function(window,undefined) {
    function ajax(options) {
        //編碼數(shù)據(jù)
        function setData() {
            //設(shè)置對(duì)象的遍碼
            function setObjData(data, parentName) {
                function encodeData(name, value, parentName) {
                    var items = [];
                    name = parentName === undefined ? name : parentName + "[" + name + "]";
                    if (typeof value === "object" && value !== null) {
                        items = items.concat(setObjData(value, name));
                    } else {
                        name = encodeURIComponent(name);
                        value = encodeURIComponent(value);
                        items.push(name + "=" + value);
                    }
                    return items;
                }
                var arr = [],value;
                if (Object.prototype.toString.call(data) == '[object Array]') {
                    for (var i = 0, len = data.length; i < len; i++) {
                        value = data[i];
                        arr = arr.concat(encodeData( typeof value == "object"?i:"", value, parentName));
                    }
                } else if (Object.prototype.toString.call(data) == '[object Object]') {
                    for (var key in data) {
                        value = data[key];
                        arr = arr.concat(encodeData(key, value, parentName));
                    }
                }
                return arr;
            };
            //設(shè)置字符串的遍碼,字符串的格式為:a=1&b=2;
            function setStrData(data) {
                var arr = data.split("&");
                for (var i = 0, len = arr.length; i < len; i++) {
                    name = encodeURIComponent(arr[i].split("=")[0]);
                    value = encodeURIComponent(arr[i].split("=")[1]);
                    arr[i] = name + "=" + value;
                }
                return arr;
            }

            if (data) {
                if (typeof data === "string") {
                    data = setStrData(data);
                } else if (typeof data === "object") {
                    data = setObjData(data);
                }
                data = data.join("&").replace("/%20/g", "+");
                //若是使用get方法或JSONP煌往,則手動(dòng)添加到URL中
                if (type === "get" || dataType === "jsonp") {
                    url += url.indexOf("?") > -1 ? (url.indexOf("=") > -1 ? "&" + data : data) : "?" + data;
                }
            }
        }
        // JSONP
        function createJsonp() {
            var script = document.createElement("script"),
                timeName = new Date().getTime() + Math.round(Math.random() * 1000),
                callback = "JSONP_" + timeName;

            window[callback] = function(data) {
                clearTimeout(timeout_flag);
                document.body.removeChild(script);
                success(data);
            }
            script.src = url + (url.indexOf("?") > -1 ? "&" : "?") + "callback=" + callback;
            script.type = "text/javascript";
            document.body.appendChild(script);
            setTime(callback, script);
        }
        //設(shè)置請(qǐng)求超時(shí)
        function setTime(callback, script) {
            if (timeOut !== undefined) {
                timeout_flag = setTimeout(function() {
                    if (dataType === "jsonp") {
                        delete window[callback];
                        document.body.removeChild(script);

                    } else {
                        timeout_bool = true;
                        xhr && xhr.abort();
                    }
                    console.log("timeout");

                }, timeOut);
            }
        }

        // XHR
        function createXHR() {
            //由于IE6的XMLHttpRequest對(duì)象是通過MSXML庫(kù)中的一個(gè)ActiveX對(duì)象實(shí)現(xiàn)的蝗砾。
            //所以創(chuàng)建XHR對(duì)象,需要在這里做兼容處理携冤。
            function getXHR() {
                if (window.XMLHttpRequest) {
                    return new XMLHttpRequest();
                } else {
                    //遍歷IE中不同版本的ActiveX對(duì)象
                    var versions = ["Microsoft", "msxm3", "msxml2", "msxml1"];
                    for (var i = 0; i < versions.length; i++) {
                        try {
                            var version = versions[i] + ".XMLHTTP";
                            return new ActiveXObject(version);
                        } catch (e) {}
                    }
                }
            }
            //創(chuàng)建對(duì)象悼粮。
            xhr = getXHR();
            xhr.open(type, url, async);
            //設(shè)置請(qǐng)求頭
            if (type === "post" && !contentType) {
                //若是post提交,則設(shè)置content-Type 為application/x-www-four-urlencoded
                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            } else if (contentType) {
                xhr.setRequestHeader("Content-Type", contentType);
            }
            //添加監(jiān)聽
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4) {
                    if (timeOut !== undefined) {
                        //由于執(zhí)行abort()方法后曾棕,有可能觸發(fā)onreadystatechange事件扣猫,
                        //所以設(shè)置一個(gè)timeout_bool標(biāo)識(shí),來忽略中止觸發(fā)的事件翘地。
                        if (timeout_bool) {
                            return;
                        }
                        clearTimeout(timeout_flag);
                    }
                    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {

                        success(xhr.responseText);
                    } else {
                        error(xhr.status, xhr.statusText);
                    }
                }
            };
            //發(fā)送請(qǐng)求
            xhr.send(type === "get" ? null : data);
            setTime(); //請(qǐng)求超時(shí)
        }
        var url = options.url || "", //請(qǐng)求的鏈接
            type = (options.type || "get").toLowerCase(), //請(qǐng)求的方法,默認(rèn)為get
            data = options.data || null, //請(qǐng)求的數(shù)據(jù)
            contentType = options.contentType || "", //請(qǐng)求頭
            dataType = options.dataType || "", //請(qǐng)求的類型
            async = options.async === undefined ? true : options.async, //是否異步申尤,默認(rèn)為true.
            timeOut = options.timeOut, //超時(shí)時(shí)間。
            before = options.before || function() {}, //發(fā)送之前執(zhí)行的函數(shù)
            error = options.error || function() {}, //錯(cuò)誤執(zhí)行的函數(shù)
            success = options.success || function() {}; //請(qǐng)求成功的回調(diào)函數(shù)
        var timeout_bool = false, //是否請(qǐng)求超時(shí)
            timeout_flag = null, //超時(shí)標(biāo)識(shí)
            xhr = null; //xhr對(duì)角
        setData();
        before();
        if (dataType === "jsonp") {
            createJsonp();
        } else {
            createXHR();
        }
    }
    window.ajax = ajax;
})(window);
上面就是封裝好的AJAX類庫(kù)衙耕∶链可以拿來直接使用,支持IE和跨域
源碼見這里
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末橙喘,一起剝皮案震驚了整個(gè)濱河市时鸵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌厅瞎,老刑警劉巖饰潜,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異和簸,居然都是意外死亡彭雾,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門锁保,熙熙樓的掌柜王于貴愁眉苦臉地迎上來薯酝,“玉大人,你說我怎么就攤上這事爽柒∥獠ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵霉赡,是天一觀的道長(zhǎng)橄务。 經(jīng)常有香客問我,道長(zhǎng)穴亏,這世上最難降的妖魔是什么蜂挪? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任重挑,我火速辦了婚禮,結(jié)果婚禮上棠涮,老公的妹妹穿的比我還像新娘谬哀。我一直安慰自己,他們只是感情好严肪,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布史煎。 她就那樣靜靜地躺著,像睡著了一般驳糯。 火紅的嫁衣襯著肌膚如雪篇梭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天酝枢,我揣著相機(jī)與錄音恬偷,去河邊找鬼。 笑死帘睦,一個(gè)胖子當(dāng)著我的面吹牛袍患,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播竣付,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼诡延,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了古胆?” 一聲冷哼從身側(cè)響起肆良,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赤兴,沒想到半個(gè)月后妖滔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡桶良,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沮翔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陨帆。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖采蚀,靈堂內(nèi)的尸體忽然破棺而出疲牵,到底是詐尸還是另有隱情,我是刑警寧澤榆鼠,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布纲爸,位于F島的核電站,受9級(jí)特大地震影響妆够,放射性物質(zhì)發(fā)生泄漏识啦。R本人自食惡果不足惜负蚊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望颓哮。 院中可真熱鬧家妆,春花似錦、人聲如沸冕茅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姨伤。三九已至哨坪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乍楚,已是汗流浹背齿税。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留炊豪,地道東北人凌箕。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像词渤,于是被迫代替她去往敵國(guó)和親牵舱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • AJAX 原生js操作ajax 1.創(chuàng)建XMLHttpRequest對(duì)象 var xhr = new XMLHtt...
    碧玉含香閱讀 3,186評(píng)論 0 7
  • 第一章 入門 基本功能:訪問和操作 dom 元素缺虐,控制頁面樣式芜壁,對(duì)頁面的事件處理,與ajax完美結(jié)合高氮,有豐富的插件...
    X_Arts閱讀 1,034評(píng)論 0 2
  • Ajax 模塊也是經(jīng)常會(huì)用到的模塊慧妄,Ajax 模塊中包含了 jsonp 的現(xiàn)實(shí),和 XMLHttpRequest ...
    對(duì)角另一面閱讀 596評(píng)論 0 1
  • Php代碼 收藏代碼 ajax通過 HTTP 請(qǐng)求加載遠(yuǎn)程數(shù)據(jù)剪芍。jQuery 底層 AJAX 實(shí)現(xiàn)塞淹。簡(jiǎn)單易用的高...
    Yumazhiyao閱讀 927評(píng)論 0 4
  • jQuery ajax - ajax() 方法 http://www.w3school.com.cn/jquery...
    光劍書架上的書閱讀 1,161評(píng)論 0 15