src\utils\http.js
封装原生 ajax 请求
// Symbol还有一个特性就是可以用作对象的属性名 ;如果我们拿Symbol作为对象的key,就不会出现属性名命名冲突的情况
const doAjax = Symbol('doAjax')
class HTTP {
[doAjax](options) {
let o = window.XMLHttpRequest
? new XMLHttpRequest()
: new ActiveXObject('Microsoft.XMLHTTP')
if (!o) {
throw new Error('您的浏览器不支持ajax')
}
let opt = options || {},
type = (opt.type || 'GET').toUpperCase(),
async = '' + opt.async === 'false' ? false : true,
dataType = opt.dataType || 'JSON',
jsonp = opt.jsonp || 'cb',
jsonCallback =
opt.jsonpCallback ||
'jQuery' + randomNum() + '_' + new Date().getTime(),
url = opt.url,
data = opt.data || null,
timeout = opt.timeout || 3000,
error = opt.error || function () {},
success = opt.success || function () {},
complete = opt.complete || function () {},
t = null
if (!url) {
throw new Error('url is required')
}
if (dataType.toUpperCase() === 'JSONP' && type !== 'GET') {
throw new Error('JSONP only support GET')
}
if (dataType.toUpperCase() === 'JSONP') {
var oScript = document.createElement('script')
oScript.src =
url.indexOf('?') === -1
? url + '?' + jsonp + '=' + jsonCallback
: url + '&' + jsonp + '=' + jsonCallback
document.body.appendChild(oScript)
document.body.removeChild(oScript)
window[jsonCallback] = (data) => {
success(data)
}
return
}
/**
* https://www.runoob.com/ajax/ajax-xmlhttprequest-onreadystatechange.html
* 每当 readyState 改变时,就会触发 onreadystatechange 事件
* 当 readyState 等于 4 且状态为 200 时,表示响应已就绪
*/
o.onreadystatechange = () => {
if (o.readyState === 4) {
if ((o.status >= 200 && o.status < 300) || o.status === 304) {
switch (dataType.toUpperCase()) {
case 'JSON':
success(JSON.parse(o.responseText))
break
case 'TEXT':
success(o.responseText)
break
case 'XML':
success(o.responseXML)
break
default:
success(JSON.parse(o.responseText))
break
}
} else {
error(o.status)
}
complete()
// 清除定时器
clearTimeout(t)
t = null
o = null
}
}
// 初始化 HTTP 请求参数
o.open(type, url, async)
type === 'POST' &&
o.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 发送 HTTP 请求
o.send(type === 'GET' ? null : formatDatas(data))
t = setTimeout(() => {
// 终止该请求
o.abort()
clearTimeout(t)
t = null
o = null
throw new Error('本次请求已超时,API地址:' + url)
}, timeout)
}
/**
* 原生 ajax 请求
* @param {*} opt
*/
ajax(opt) {
this[doAjax](opt)
}
post(url, data, dataType, successCB, errorCB, completeCB) {
this[doAjax]({
type: 'POST',
url: url,
data: data,
dataType: dataType,
success: successCB,
error: errorCB,
complete: completeCB,
})
}
get(url, dataType, successCB, errorCB, completeCB) {
this[doAjax]({
type: 'GET',
url: url,
dataType: dataType,
success: successCB,
error: errorCB,
complete: completeCB,
})
}
}
/**
* 格式化请求参数
* @param {*} obj
* @returns
*/
function formatDatas(obj) {
var str = ''
for (var key in obj) {
str += key + '=' + obj[key] + '&'
}
return str.replace(/&$/, '')
}
function randomNum() {
var num = ''
for (var i = 0; i < 20; i++) {
num += Math.floor(Math.random() * 10)
}
return num
}
export default HTTP
src\models\index.js
封装业务数据请求
import HTTP from '../utils/http'
/**
* 使用封装好的 HTTP
*/
class IndexModel extends HTTP {
getGoodsList () {
// 返回 Promise 请求
return new Promise((resolve, reject) => {
this.ajax({
url: '/api/goods',
type: 'POST',
dataType: 'JSON',
success(data) {
resolve(data)
}
})
})
}
}
export default IndexModel
src\js\index.js
使用封装好的网络请求类。
import IndexModel from '../models/index'
const indexModel = new IndexModel()
indexModel.getGoodsList().then(res => {
console.log(res);
})
扩展阅读