第 40 題:如何實(shí)現(xiàn)一個 ajax疏橄?

主要使用以下文件

config.js:ajax 請求配置核心文件

loading.js:element-ui 請求加載動畫

index.js:二次封裝 config.js 請求并導(dǎo)出該方法禾嫉,配置請求攔截器昌执、響應(yīng)攔截器

index.vue:調(diào)用 ajax 的示例頁面

注意:推薦在 api 目錄統(tǒng)一管理所有接口妙同,如果遇到報錯請調(diào)整正確引用路徑

config.js

import loading from './loading.js'; // 加載動畫類

const animation = false; // 接口加載動畫
const intTimer = 10; // 接口請求超時時間(秒)

class Config {
    constructor(data) {
        this.method = data.method;
        this.url = data.url;
        this.param = data.param || {};
        this.header = data.header || {};
        this.interceptors = data.interceptors;
        this.response = data.response;

        return this.filter();
    }

    // 創(chuàng)建XHR對象
    createXHR() {
        if (window.XMLHttpRequest) {
            // code for IE7+, Firefox, Chrome, Opera, Safari
            return new XMLHttpRequest();
        } else {
            // code for IE6, IE5
            return new ActiveXObject('Microsoft.XMLHTTP');
        }
    }

    // HTTP請求
    xhrRequest(header, method, url, param, async, interceptors, response) {
        return new Promise(resolve => {
            var xhr = this.createXHR();
            if (animation == true) {
                loading.requestStart(); // 執(zhí)行動畫
            }

            // 請求攔截
            if (interceptors({ header, method, url: this.url, param: this.param, async })) {
                xhr.open(method, url, async);
                xhr.timeout = 1000 * intTimer; //設(shè)置xhr請求的超時時間
                Object.keys(header).map(key => {
                    xhr.setRequestHeader(key, header[key]);
                });
                xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; application/json; charset=utf-8');
                xhr.send(param);
                xhr.onreadystatechange = () => {
                    if (xhr.readyState == 4 && xhr.status == 200) {
                        loading.requestEnd(); // 結(jié)束動畫
                        try {
                            let data = JSON.parse(xhr.responseText);

                            resolve(response(data, { header, method, url: this.url, param: this.param, async }));
                        } catch (error) {
                            console.log('接口返回沒有任何信息!');
                            resolve(false);
                        }
                    } else {
                        return 'request is unsucessful ' + xhr.status;
                    }
                };
            } else {
                console.error('request interceptor', '請求未發(fā)出, 請求攔截器已生效!');
            }

            // 請求超時方法
            xhr.ontimeout = function(e) {
                console.log('接口請求超時!');
                loading.requestEnd(); // 結(jié)束動畫
            };

            // 請求錯誤方法
            xhr.onerror = function(e) {
                console.log('接口請求失敗');
                loading.requestEnd(); // 結(jié)束動畫
            };
        });
    }

    // 參數(shù)轉(zhuǎn)換
    convParams(param) {
        let mark = '?';
        let hasMark = this.url.indexOf(mark) > 0; // 是否包含特殊字符
        if (hasMark) {
            mark = '&';
        }

        let newParams = '';
        let i = 0;
        for (let key in param) {
            if (i > 0) {
                newParams += `&${key}=${param[key]}`;
            } else {
                newParams += `${mark}${key}=${param[key]}`;
            }
            i++;
        }
        return newParams;
    }

    // 數(shù)據(jù)GET杈湾、POST請求處理
    filter() {
        let obj = {
            header: this.header,
            method: this.method,
            url: this.url,
            param: {},
            async: true,
            interceptors: this.interceptors,
            response: this.response
        };

        // 接口名稱拼接位置:(1、url) (2费变、param)

        let newParams = this.convParams(this.param);
        if (this.method == 'GET') {
            obj.url += newParams;
        } else {
            newParams = newParams.replace('?', '');
            obj.param = newParams;
        }

        return this.xhrRequest(obj.header, obj.method, obj.url, obj.param, obj.async, obj.interceptors, obj.response);
    }
}

export default Config;

loading.js

import { Loading } from 'element-ui';

class animation {
    constructor() {
        this.needLoadingRequestCount = 0;
        this.loading
    }

    /**
     * 動畫開始
     */
    requestStart() {
        if (this.needLoadingRequestCount === 0) {
            this.loading = Loading.service({
                lock: true,
                text: 'loading...',
                background: 'rgba(0, 0, 0, 0.7)'
            });
        }
        this.needLoadingRequestCount++;
    }

    /**
     * 動畫結(jié)束
     */
    requestEnd() {
        if (this.needLoadingRequestCount <= 0) return;
        this.needLoadingRequestCount--;
        if (this.needLoadingRequestCount === 0) {
            this.loading.close();
        }
    }
}


export default new animation()

index.js

import Config from './config.js';

/**
 * 接口請求方法
 * @func request
 * @param {Object} method 請求方式: 僅支持GET摧扇、POST
 * @param {String} url 請求地址
 * @param {Object} param 請求參數(shù)
 */
let request = option => {
    // 配置默認(rèn)請求參數(shù)

    return new Config({
        header: {
            Authorization: 'APPCODE edc39cc1dc5f4c139498322115b99e51'
        },
        method: option.method,
        url: option.url,
        param: option.param,
        interceptors: interceptors,
        response: response
    });
};

/**
 * 請求攔截器
 * @func interceptors
 */
let interceptors = config => {
    return true;
};

/**
 * 響應(yīng)攔截器
 * @func response
 */
let response = (data, config) => {
    let res;

    // 處理返回格式
    if (data.res) {
        res = data.res;
    } else if (data.data) {
        res = data.data;
    } else {
        res = data;
    }
    return res;
};

export default request;

index.vue

<script>
import request from './index.js';

export default {
    mounted() {
        new request({
            method: 'GET', // 請求方式: GET、POST
            url: 'http://10.10.10.10/xxx/xxx', // 請求地址
            param: {} // 請求參數(shù)
        }).then(res => {
            console.log('res', res);
        });
    }
};
</script>

文章的內(nèi)容/靈感都從下方內(nèi)容中借鑒

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挚歧,一起剝皮案震驚了整個濱河市扛稽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滑负,老刑警劉巖庇绽,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異橙困,居然都是意外死亡瞧掺,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進(jìn)店門凡傅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辟狈,“玉大人,你說我怎么就攤上這事夏跷『咦” “怎么了?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵槽华,是天一觀的道長壹蔓。 經(jīng)常有香客問我,道長猫态,這世上最難降的妖魔是什么佣蓉? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮亲雪,結(jié)果婚禮上勇凭,老公的妹妹穿的比我還像新娘。我一直安慰自己义辕,他們只是感情好虾标,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著灌砖,像睡著了一般璧函。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上基显,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天蘸吓,我揣著相機(jī)與錄音,去河邊找鬼续镇。 笑死美澳,一個胖子當(dāng)著我的面吹牛销部,可吹牛的內(nèi)容都是我干的摸航。 我是一名探鬼主播制跟,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼酱虎!你這毒婦竟也來了雨膨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤读串,失蹤者是張志新(化名)和其女友劉穎聊记,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恢暖,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡排监,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了杰捂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舆床。...
    茶點(diǎn)故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嫁佳,靈堂內(nèi)的尸體忽然破棺而出挨队,到底是詐尸還是另有隱情,我是刑警寧澤蒿往,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布盛垦,位于F島的核電站,受9級特大地震影響瓤漏,放射性物質(zhì)發(fā)生泄漏腾夯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一蔬充、第九天 我趴在偏房一處隱蔽的房頂上張望俯在。 院中可真熱鬧,春花似錦娃惯、人聲如沸跷乐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愕提。三九已至,卻和暖如春皿哨,著一層夾襖步出監(jiān)牢的瞬間浅侨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工证膨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留如输,地道東北人。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像不见,于是被迫代替她去往敵國和親澳化。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評論 2 361

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