使用Promise封装XMLHttpRequest做异步请求

This commit is contained in:
WIN-VSNMD38DUOC\Administrator
2024-03-15 10:28:39 +08:00
parent 25817132fd
commit f65fcbac7a
3 changed files with 478 additions and 31 deletions

View File

@@ -1,4 +1,10 @@
class Fmt{
static _fmt_token_key = "_fmt_token_value";
/**
* 缓存配置 sessionsessionStorage locallocalStorage
* @type {string}
*/
static cache_config = "session";
constructor() {
}
/**
@@ -11,5 +17,442 @@ class Fmt{
return window.location.protocol + '//' + window.location.host;
}
return window.location.protocol + '//' + window.location.host + '/' + webName;
};
/**
* 缓存封装
* @type {{
* set: function(String, *): void,
* get: function(String): string,
* clear: function(): void,
* remove: function(String): void,
* key: function(Number): string
* }}
*/
static cache = {
/**
* 设置缓存
* @param {String} key
* @param value
*/
set: (key, value) => {
const config = Fmt.cache_config;
const storage = config === 'session' ?
window.sessionStorage : window.localStorage;
storage.setItem(key, value);
},
/**
* 获取缓存
* @param {String} key
* @returns {string}
*/
get: (key) => {
const config = Fmt.cache_config;
const storage = config === 'session' ?
window.sessionStorage : window.localStorage;
return storage.getItem(key);
},
/**
* 清除缓存
* @param {String} key
*/
remove: (key) => {
const config = Fmt.cache_config;
const storage = config === 'session' ?
window.sessionStorage : window.localStorage;
storage.removeItem(key);
},
/**
* 获取缓存key
* @param {Number} num
* @returns {string}
*/
key: (num) => {
const config = Fmt.cache_config;
const storage = config === 'session' ?
window.sessionStorage : window.localStorage;
return storage.key(num);
},
/**
* 此方法会清空整个浏览器的LocalStorage缓存
*/
clear: () => {
const config = Fmt.cache_config;
const storage = config === 'session' ?
window.sessionStorage : window.localStorage;
storage.clear();
}
};
/**
* 常用工具方法封装
* @type {{isEmpty: function(*): boolean, typeOf: function(*): string}}
*/
static utils = {
/**
* 获得对象真正的类型
* 可检测出Array,Object,Function,String,Number,Boolean,Date,Null,Undefined,HTMLDivElement(Dom节点都包含HTML)等
* @param obj
* @returns {string}
*/
typeOf: (obj) => Object.prototype.toString.call(obj).slice(8, -1),
/**
* 定义判断为空函数可判断function(){}0''[]{}undefinednull
* @param data
* @returns {boolean}
*/
isEmpty: (data) => {
let type = this.utils.typeOf(data);
if (!data) {
return true;
} else if (type === 'Function') {
return (data.toString().replace(/\s+/g, '').match(/{.*}/g)[0] === '{}');
} else if (type === 'Array') {
return data.join('') === '';
} else if (type === 'Object') {
return (Object.keys(data).length === 0)
} else {
return false;
}
},
/**
* 该函数是深度拷贝函数,返回一个一模一样的对象
* @param data
* @returns {*|Date|{}}
*/
clone: (data) => {
let cloneObj = (obj) => {
if (obj === null) {
return null;
} else if (typeof obj !== 'object') {
return obj;
} else if (obj.constructor === Date) {
return new Date(obj);
} else {
let newObj = {};
for (let k in obj) {
if (obj[k] == null) {
newObj[k] = null;
} else if ((typeof obj[k]) == 'object' && !obj[k].nodeType) {
newObj[k] = axClone(obj[k]);
if (obj[k] instanceof Array) {
let newArray = [];
for (let i of obj[k]) {
newArray.push(axClone(i));
}
newObj[k] = newArray;
}
} else {
newObj[k] = obj[k];
}
}
return newObj;
}
}
if (Array.isArray(data)) {
return data.map(k => cloneObj(k));
} else {
return cloneObj(data);
}
},
/**
* 扩展source相同属性的值去覆盖target, target如果没有这个属性就新增
* @param {Object} target
* @param {Object} source
* @returns {Object}
*/
extend: (target, source) => {
if(this.utils.typeOf(target) !== 'Object') return null;
if(this.utils.typeOf(source) !== 'Object') return null;
for (const key in source) {
// 使用for in会遍历数组所有的可枚举属性包括原型。
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
return target;
},
/**
* 判断选择器类型
* @param str
* @returns {string|boolean}
*/
strType: (str) => {
if (typeof str !== 'string') {
console.error('Argument must be a string!')
return false;
}
str = str.trim();
let isUpperCase = (letter) => {
if (letter >= 'A' && letter <= 'Z') {
return true;
}
},
type = '';
if (str) {
if (str.includes(' ')) {
type = 'level';
} else {
if (str.startsWith('#')) {
type = 'id';
} else if (str.startsWith('.')) {
type = 'class';
} else if (str.startsWith('[') && str.endsWith(']')) {
type = 'name';
} else if ([...str].every(i => isUpperCase(i))) {
type = 'node';
}
}
}
return type;
},
/**
* 将#id转成DOM
* @param elem
* @returns {*|boolean}
*/
idToDom: (elem) => {
let type = this.utils.typeOf(elem);
if (!elem) {
console.warn('Node selector is empty!');
return false;
} else if (type === 'String') {
let trim = elem.trim();
if (this.utils.strType(trim)) {
if (this.utils.strType(trim) === 'name' && !trim.includes('=')) {
trim = trim.slice(0, 1) + 'name=' + trim.slice(1);
}
return document.querySelector(trim);
} else {
console.warn('No node is found with this string!');
return false;
}
} else if (type.includes('HTML')) {
return elem;
} else {
return false;
}
},
/**
* 从表单控件取值用于校验判断适合的控件checkbox、radio、select-multiple和file
* @param name
* @param type
* @param format
* @param form
* @param separator
* @returns {*[]|boolean}
*/
multiValues: (name, type = 'checkbox', format = 'array', form, separator = ',') => {
let inputs,
values = [],
parent = form ? this.utils.idToDom(form) : '';
if (this.utils.strType(name) === 'NodeList' || this.utils.strType(name) === 'Array') {
if (type.includes('select') || type === 'file') {
console.warn('Can not be an node array in this type!');
return false;
}
inputs = name;
} else if (typeof name == 'object' || (this.utils.strType(name) && this.utils.strType(name) !== 'name')) {
let dom = this.utils.idToDom(name);
if (type.includes('select') || name.nodeName === 'SELECT') {
type = 'select';
inputs = dom.options;
} else if (type === 'file' || dom.type === 'file') {
type = 'file';
inputs = [dom];
} else {
inputs = [...dom.querySelectorAll('input')];
}
} else {
let selector = '';
if (this.utils.strType(name) === 'name') {
selector = name.replace('[', '[name=');
} else {
selector = `[name=${name}]`;
}
if (type.includes('select')) {
inputs = parent ? parent.querySelector(selector).options : document.querySelector(selector).options;
} else if (type === 'file') {
inputs = parent ? [parent.querySelector(selector)] : [document.querySelector(selector)];
} else {
inputs = parent ? [...parent.querySelectorAll(selector)] : [...document.querySelectorAll(selector)];
}
}
for (let i = 0; i < inputs.length; i++) {
let condition,
item = inputs[i];
if (type.includes('select')) {
condition = item.selected;
} else {
condition = item.checked;
}
if (type === 'file') {
values = [...item.files];
} else {
if (condition) {
values.push(item.value);
}
}
}
if (format === 'string') {
values = values.join(separator)
}
return values;
},
/**
* 表单序列化,支持将表单值序列化为以“&”连接的字符串,和对象数组[{name:'',value:''},...]
* @param element
* @param type
* @param separator
* @returns {{}}
*/
serialize: (element, type = "string", separator = ',') => {
let inputs,
items = [],
output;
if (Array.isArray(element)) {
inputs = element;
} else {
inputs = [...this.utils.idToDom(element).querySelectorAll('[name]')].filter(i => ['INPUT', 'SELECT', 'TEXTAREA'].includes(i.nodeName) && i.name && !i.name.includes('_ax_alt'));
}
inputs.forEach(i => {
let have = items.find(k => k.name === i.name);
if (have) {
if (i.type === 'checkbox' || i.type === 'radio') {
have.dom.push(i);
}
} else {
items.push({ name: i.name, type: i.type, dom: [i] })
}
});
items.forEach(i => {
if (i.type === 'file') {
i.value = this.utils.multiValues(i.dom[0], 'file', 'array');
} else if (i.type === 'checkbox') {
i.value = this.utils.multiValues(i.dom, 'checkbox', 'string', '', separator);
} else if (i.type === 'radio') {
i.value = this.utils.multiValues(i.dom, 'radio', 'string');
} else if (i.type.includes('select')) {
i.value = this.utils.multiValues(i.dom[0], 'select', 'string', '', separator);
} else {
i.value = i.dom[0].value;
}
});
if (type === 'string') {
let str = '';
items.forEach(k => {
str += '&' + k.name + '=' + k.value;
});
output = str;
} else if (type === 'json') {
let obj = {}
items.forEach(k => {
obj[k.name] = k.value;
});
output = obj;
} else if (type === 'array') {
items.forEach(k => {
delete k.type;
delete k.dom;
})
output = items;
}
return output;
}
};
/**
* XMLHttpRequest封装
* @param {{url, data, method, responseType, contentType, timeout, headers}} options
* @returns {Promise<unknown>}
*/
#axiosPrivate(options){
let data = options.data;
let url = options.url;
let method = options.method || 'GET';
let responseType = options.responseType || 'json';
let contentType = options.contentType || 'application/x-www-form-urlencoded';
let timeout = options.timeout || 0;
/**
* 序列化参数
* @param data
* @returns {string}
*/
let serialize = (data) => {
if (Fmt.utils.isEmpty(data)) return '';
let pairs = [];
for (let name in data) {
if (!data.hasOwnProperty(name)) continue;
if (Fmt.utils.typeOf(data[name]) === 'Function') continue;
let value = data[name].toString();
name = encodeURIComponent(name);
value = encodeURIComponent(value);
pairs.push(name + '=' + value);
}
return pairs.join('&');
}
/**
* 创建xhr请求对象
* @returns {XMLHttpRequest || ActiveXObject}
*/
let xhrObj = () => {
let xhr = '';
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
return xhr;
}
return new Promise((resolve, reject) => { // promise封装
let xhr = xhrObj();
let params = null;
xhr.onreadystatechange = handler;
if (method.toUpperCase() === 'GET') {
url = url + '?now=' + new Date().getTime() + '&' + serialize(data);
} else if (method.toUpperCase() === 'POST') {
params = serialize(data);
}
xhr.responseType = responseType;
xhr.timeout = timeout;
xhr.open(method, url);
xhr.setRequestHeader('Content-Type', contentType);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader("Access-Control-Allow-Origin","*");
if(!Fmt.utils.isEmpty(options.headers) && Fmt.utils.typeOf(options.headers) === 'Object'){
for (let key in options.headers) {
xhr.setRequestHeader(key, options.headers[key]);
}
}
xhr.send(params);
function handler() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);//正确回调
} else {
reject(new Error(this.statusText));//错误回调
}
}
})
}
/**
* XMLHttpRequest封装
* <pre>
* 使用方式:
* const options = {
* url: Fmt.ctx() + '/salt',
* data: {username: username},
* method: 'post'
* };
* Fmt.axios(options).then((res) => {
* console.warn(res)
* }).catch((err) => {console.warn(err)});
* </pre>
* @param {{url, data, method, responseType, contentType, timeout, headers}} options
* @returns {Promise<unknown>}
*/
static axios(options){
let fmt = new Fmt();
return fmt.#axiosPrivate(options);
}
}

View File

@@ -88,20 +88,21 @@
<script th:src="@{/axui-v2.1.1/js/ax.js}" type="text/javascript" charset="utf-8"></script>
<script th:src="@{/common/js/basic.js}" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" th:inline="javascript" charset="utf-8">
let fileDel = (obj) => {
const fileDel = (obj) => {
const path = obj.getAttribute("value");
let formData = {path: path};
axAjax({
url: '/fmt/download/delete',
data: formData,
type: 'post',
success: function (result) {
window.location.href = '/fmt/download/index';
}
const options = {
url: Fmt.ctx() + '/download/delete',
data: {path: path},
method: 'post'
};
Fmt.axios(options).then((result) => {
window.location.href = Fmt.ctx() + '/download/index';
}).catch((err) => {
new axMessage({content: err, result: 'error', iconShow: true}).show();
});
}
let fileDown = (obj) => {
const fileDown = (obj) => {
const path = obj.getAttribute("value");
window.open(Fmt.ctx() + '/download/execute?path=' + encodeURIComponent(path) + '&temp=' + false);
};
@@ -109,7 +110,7 @@
window.onload = () => {
document.getElementById("search").onclick = () => {
const keyboard = document.getElementById("keyboard").value;
window.location.href = '/fmt/download/index?keyboard=' + keyboard;
window.location.href = Fmt.ctx() + '/download/index?keyboard=' + keyboard;
}
document.getElementById("zipDownBtn").onclick = () => {
@@ -125,18 +126,19 @@
new axMessage({content: '请选择要下载的文件',result: 'warning',iconShow: true}).show();
return false;
}
let formData = {filenames: filenames.join(",")};
let message = new axMessage({content: '',result: 'success',iconShow: true});
message.update({content: '正在根据所选文件创建压缩包......', result: 'success'}).show();
axAjax({
url: '/fmt/download/packZip',
data: formData,
type: 'post',
success: function (result) {
const data = result.content;
message.update({content: '压缩包' + data.filename + "创建完成,准备下载文件......", result: 'success'}).show();
window.open(Fmt.ctx() + '/download/execute?path=' + encodeURIComponent(data.path) + '&temp=' + true);
}
const options = {
url: Fmt.ctx() + '/download/packZip',
data: {filenames: filenames.join(",")},
method: 'post'
};
Fmt.axios(options).then((result) => {
message.update({content: '压缩包' + result.filename + "创建完成,准备下载文件......", result: 'success'}).show();
window.open(Fmt.ctx() + '/download/execute?path=' + encodeURIComponent(result.path) + '&temp=' + true);
}).catch((err) => {
console.log(err);
new axMessage({content: err, result: 'error', iconShow: true}).show();
});
}
@@ -153,14 +155,15 @@
new axMessage({content: '请选择要删除的文件',result: 'warning',iconShow: true}).show();
return false;
}
let formData = {filenames: filenames.join(",")};
axAjax({
url: '/fmt/download/batchDel',
data: formData,
type: 'post',
success: function (result) {
window.location.href = '/fmt/download/index';
}
const options = {
url: Fmt.ctx() + '/download/batchDel',
data: {filenames: filenames.join(",")},
method: 'post'
};
Fmt.axios(options).then((result) => {
window.location.href = Fmt.ctx() + '/download/index';
}).catch((err) => {
new axMessage({content: err, result: 'error', iconShow: true}).show();
});
}
}

View File

@@ -1,7 +1,7 @@
> v1.0.0
```
使用SpringBoot3.1.1 + Jdk17搭建项目
集成AXUIv2.0.14实现文件上传、文件下载
集成AxUIv2.0.14实现文件上传、文件下载
集成RocksDBv8.3.2使用RocksDB做嵌入式缓存中间件
```
> v1.1.0
@@ -11,5 +11,6 @@
```
> v1.2.0
```
AXUIv2.0.14升级到AXUIv2.1.1
AxUIv2.0.14升级到v2.1.1
使用Promise封装XMLHttpRequest做异步请求
```