Skip to content

Instantly share code, notes, and snippets.

@chiwent
Forked from yangfch3/ajax.js
Last active October 18, 2018 13:24
Show Gist options
  • Save chiwent/ea3e8881d15c5c5299aa327490cd6ba4 to your computer and use it in GitHub Desktop.
Save chiwent/ea3e8881d15c5c5299aa327490cd6ba4 to your computer and use it in GitHub Desktop.
ajax 请求封装
var Ajax = (function() {
var methodsList = ['get', 'post', 'head', 'options', 'put', 'connect', 'trace', 'delete'];
/**
* Ajax
* @param {String} url
* @param {Function} callback
* @param {Object/String} data
* @param {Object} options
*
*/
function Ajax(url, callback, data, options) {
// 顺序:new XHR --> onreadystatechange ---> open() ---> other callback or property ---> send()
var xhr = (function() {
// 使用 typeof 不会报错
if (typeof XMLHttpRequest !== undefined) {
return new XMLHttpRequest();
} else if (typeof ActiveXObject !== undefined) {
if (typeof arguments.callee.activeXString !== 'string') {
var versions = ['MSXML2.XMLHttp.6.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp'],
i, len;
for (i = 0, len = versions.length; i < len; i++) {
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (error) {
console.log('Your Browser do not support ' + versions[i] + '.');
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error('没有可用的 AJAX 对象构造器');
}
})();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
try {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
if (callback) {
callback(xhr.responseText, xhr.status, xhr);
} else {
console.log(xhr);
}
} else {
console.error('请求错误: ' + xhr.status + ' ' + xhr.statusText);
}
} catch (error) {
console.error('回调函数内部发生错误,请检查回调函数!');
}
}
};
var method = (options && options.method && methodsList.indexOf(options.method.toLowerCase()) + 1) ? options.method : 'get';
if (method.toLowerCase() === 'get') {
if (typeof data === 'object' && data !== null) {
url = (function() {
var queryArr = [];
for (var prop in data) {
if (data.hasOwnProperty(prop)) {
queryArr.push(encodeURIComponent(prop) + '=' + encodeURIComponent(data[prop]));
}
}
return (url + '?' + queryArr.join('&'));
})();
data = null;
} else if (typeof data === 'string') {
data = data.indexOf('?') === 0 ? data : '?' + data;
url = url + data;
data = null;
} else {
data = null;
}
} else {
// 对于 POST,data 可以是null、字符串、文件(表单文件控件取得)、FormData、ArrayBuffer
if (data instanceof FormData || data instanceof File || data instanceof ArrayBuffer) {
data = data;
} else if (typeof data === 'object') {
data = function() {
var serializeArr = [];
for (var prop in data) {
if (data.hasOwnProperty(prop)) {
serializeArr.push(encodeURIComponent(prop) + '=' + encodeURIComponent(data[prop]));
}
}
return serializeArr.join('&');
}();
} else if (typeof data === 'string') {
data = data;
} else {
data = null;
}
}
var ifAsync = (options && options.async && options.async === false) ? false : true;
try {
xhr.open(method, url, ifAsync);
// defining onload, onprogress, error and withCredentials
(function() {
for (var prop in options) {
if (options.hasOwnProperty(prop)) {
if (prop === 'onload') {
xhr.onload = function() {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
options[prop].call(xhr, xhr.responseText, xhr.status, xhr);
} else {
console.log('load event -- Request was unsuccessful: ' + xhr.status);
}
};
} else if (prop === 'onprogress' || prop === 'ontimeout' || prop === 'onerror' || prop === 'onabort' || prop === 'onloadstart' || prop === 'onloadend') {
xhr[prop] = function(e) {
options[prop].call(xhr, e, xhr.responseText, xhr.status, xhr);
}
} else if (prop === 'timeout' || prop === 'withCredentials') {
xhr[prop] = options[prop];
} else if (prop === 'overrideMimeType') {
xhr.overrideMimeType(options[prop]);
} else if (prop === 'requestHeader') {
for (var header in options[prop]) {
if (options[prop].hasOwnProperty(header)) {
xhr.setRequestHeader(header, options[prop][header]);
}
}
} else if (prop === 'upload') {
// 使用 Ajax 上传数据的状态事件回调函数,可用 upload.onprogress 实现上传进度条,当然需要服务器支持返回上传进度
for (var uploadEvent in options[prop]) {
if (options[prop].hasOwnProperty(uploadEvent)) {
xhr.upload[uploadEvent] = options[prop][uploadEvent];
}
}
}
}
}
})();
xhr.send(data);
} catch(e) {
console.error('可能由于跨域限制,导致无法发起 Ajax 请求。');
xhr = null;
}
return xhr;
}
Ajax.get = function (url, callback, data, options) {
if (options) {
options.method = 'get';
} else {
options = {
method: 'get'
}
}
return Ajax(url, callback, data, options);
};
// 如果使用 POST 上传的是文本数据,请在 options 内设置 {requestHeader: {'Content-Type': 'application/x-www-form-urlencoded'}}
Ajax.post = function (url, callback, data, options) {
if (options) {
options.method = 'post';
} else {
options = {
method: 'post'
}
}
data = data ? data : '';
if (typeof data === 'string' || data.constructor === Object) {
if (options.requestHeader) {
options.requestHeader['Content-Type'] = 'application/x-www-form-urlencoded';
} else {
options.requestHeader = {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
}
return Ajax(url, callback, data, options);
};
Ajax.getJSON = function (url, callback, data, options) {
var newCallback = function (responseText, status, xhr) {
try {
var responseJSONObj = JSON.parse(responseText);
if (callback) {
callback(responseJSONObj, status, xhr);
} else {
console.log(xhr);
}
} catch(e) {
console.error('数据不符合要求,无法转为 JSON 对象!请确保接口返回数据为 JSON 格式。');
}
};
return Ajax(url, newCallback, data, options);
}
return Ajax;
})();
// 所有事件与callback都接受三个参数:responseText, status, xhr
// var callback = function(responseText, status, xhr) {
// //...
// };
// var options = {
// method: 'get',
// async: false,
// timeout: 2000,
// ontimeout: ontimeout,
// onerror: onerror,
// onabort: onabort,
// onprogress: onprogress,
// onload: onload,
// onloadstart: onloadstart,
// onloadend: onloadend,
// onprogress: onprogress,
// withCredentials: true,
// requestHeader: {
// xxx: yyy,
// ...
// },
// upload: {
// onloadstart: xxx
// onloadend: xxx
// onprogress: xxx
// }
// //...
// };
// 如果使用 POST 上传的是文本数据,请在 options 内设置 {requestHeader: {'Content-Type': 'application/x-www-form-urlencoded'}}
// Ajax(/* ... */);
// new Ajax(/* ... */);
// Ajax.get(/* ... */);
// Ajax.post(/* ... */);
// Ajax.getJSON(/* ... */));
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta http-equiv="Access-Control-Allow-Origin" content="*">
<meta charset="utf-8">
<meta content="initial-scale=1,maximum-scale=1,user-scalable=no,width=device-width" name="viewport" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit">
<meta http-equiv="Cache-Control" content="no-siteapp" />
<title>Hi</title>
</head>
<body>
<input id="upFile" , type="file" value="选择文件" name="upFile">
<br/>
<!-- 当然,如果你要考虑兼容性,那么着了可以选择非 progress -->
<progress id="progress" value="0"></progress>
<button id="button">Start uploading</button>
<span id="display"></span>
<!-- 见我的 gist 里的 ajax.js -->
<script src="./ajax.js"></script>
<script>
var progressBar = document.getElementById("progress"),
loadBtn = document.getElementById("button"),
display = document.getElementById("display");
upFile = document.getElementById("upFile");
function upload(data) {
// 其他可用于文件上传操作练习的 API:http://malsup.com/jquery/form/file-echo2.php
var xhr = new Ajax('https://zinoui.com/demo/progress-bar/upload.php', null, data, {
method: 'post',
'Content-Type': 'multipart/form-data',
// 多余地设置 withCredentials 为 true 可能会造成报错
// withCredentials: true,
upload: {
onprogress: function(e) {
if (e.lengthComputable) {
progressBar.max = e.total;
progressBar.value = e.loaded;
display.innerText = Math.floor((e.loaded / e.total) * 100) + '%';
}
},
onloadstart: function(e) {
progressBar.value = 0;
display.innerText = '0%';
},
onloadend: function(e) {
progressBar.value = e.loaded;
loadBtn.disabled = false;
loadBtn.innerHTML = 'Start uploading';
}
}
});
}
function buildFormData() {
var fd = new FormData();
fd.append('file', upFile.files[0]);
// for (var i = 0; i < 3000; i += 1) {
// fd.append('data[]', Math.floor(Math.random() * 999999));
// }
return fd;
}
loadBtn.addEventListener("click", function(e) {
this.disabled = true;
this.innerHTML = "Uploading...";
upload(buildFormData());
});
// 服务器端代码
// <?php
// header('Access-Control-Allow-Origin: *');
// header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
// foreach($_FILES as $file) {
// $n = $file['name'];
// $s = $file['size'];
// if (is_array($n)) {
// $c = count($n);
// for ($i=0; $i < $c; $i++) {
// echo "<br>uploaded: " . $n[$i] . " (" . $s[$i] . " bytes)";
// }
// }
// else {
// echo "<br>uploaded: $n ($s bytes)";
// }
// }
// ?>
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment