第 40 题:如何实现一个 ajax?
主要使用以下文件
config.js:ajax 请求配置核心文件
loading.js:element-ui 请求加载动画
index.js:二次封装 config.js 请求并导出该方法,配置请求拦截器、响应拦截器
index.vue:调用 ajax 的示例页面
注意:推荐在 api 目录统一管理所有接口,如果遇到报错请调整正确引用路径
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();
}
// 创建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(); // 执行动画
}
// 请求拦截
if (interceptors({ header, method, url: this.url, param: this.param, async })) {
xhr.open(method, url, async);
xhr.timeout = 1000 * intTimer; //设置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(); // 结束动画
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', '请求未发出, 请求拦截器已生效!');
}
// 请求超时方法
xhr.ontimeout = function(e) {
console.log('接口请求超时!');
loading.requestEnd(); // 结束动画
};
// 请求错误方法
xhr.onerror = function(e) {
console.log('接口请求失败');
loading.requestEnd(); // 结束动画
};
});
}
// 参数转换
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;
}
// 数据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++;
}
/**
* 动画结束
*/
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 请求参数
*/
let request = option => {
// 配置默认请求参数
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;
};
/**
* 响应拦截器
* @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: {} // 请求参数
}).then(res => {
console.log('res', res);
});
}
};
</script>
文章的内容/灵感都从下方内容中借鉴
-
【持续维护/更新 500+前端面试题/笔记】https://github.com/noxussj/Interview-Questions/issues
-
【大数据可视化图表插件】https://www.npmjs.com/package/ns-echarts
-
【利用 THREE.JS 实现 3D 城市建模(珠海市)】https://3d.noxussj.top/