@tanshenghu/web-utils
Version:
web公共方法
750 lines (658 loc) • 24.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.$getScript = exports.$jsonp = exports.$patch = exports.$put = exports.$post = exports.$head = exports.$delete = exports.$get = exports.Ajax = undefined;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /* eslint-disable */
/**
** @Author: 谭生虎 TanShenghu tanshenghu@163.com
** @Update: 2018-05-10
** @Description: ajax/fetch/socket/getScript数据请求方法封装 不支持jsonp如果后期有这需求可以添加
** 因在request添加cookie, conent-type等字段信息所以只适合熙牛项目
** special: intactModel<取整个respnse数据> customTip<自定义异常提示框> noHeaders<不带header信息> cover<默认无,传false不需要loading层> duration<提示框延迟关闭>
** hasFetchLoading=false<项目不需要loading层>
*/
var _xmlhttprequest = require('./xmlhttprequest');
Object.defineProperty(exports, 'Ajax', {
enumerable: true,
get: function get() {
return _interopRequireDefault(_xmlhttprequest).default;
}
});
var _common = require('../common');
var _common2 = _interopRequireDefault(_common);
var _orderly = require('../orderly');
var _orderly2 = _interopRequireDefault(_orderly);
var _style = require('./style');
var _style2 = _interopRequireDefault(_style);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var isType = _common2.default.isType;
var G = globalThis;
var webConfig = G.webConfig || {};
var fetchingCount = void 0;
var coverElement = null;
var DATATYPES = ['json', 'text', 'blob', 'arrayBuffer']; // 数据流转换类型
var noop = function noop() {};
var hasSupperAbort = !!G.AbortController;
var baseUrl = G.localStorage.getItem('ajaxBaseUrl');
var aloneBaseUrl = G.localStorage.getItem('ajaxAloneBaseUrl');
var defaultHeaders = {};
var injectBeforeSend = void 0;
var injectResponseCallback = void 0;
var injectResponseErrorCallback = void 0;
var defaultFetchOptions = {};
var request = function request(options) {
var _options$url = options.url,
url = _options$url === undefined ? location.pathname : _options$url,
_options$type = options.type,
method = _options$type === undefined ? 'get' : _options$type,
_options$data = options.data,
data = _options$data === undefined ? {} : _options$data,
_options$headers = options.headers,
headers = _options$headers === undefined ? {} : _options$headers,
_options$dataType = options.dataType,
dataType = _options$dataType === undefined ? 'json' : _options$dataType,
_options$special = options.special,
special = _options$special === undefined ? {} : _options$special,
_options$beforeSend = options.beforeSend,
beforeSend = _options$beforeSend === undefined ? noop : _options$beforeSend,
_options$success = options.success,
success = _options$success === undefined ? noop : _options$success,
_options$error = options.error,
error = _options$error === undefined ? noop : _options$error,
_options$complete = options.complete,
complete = _options$complete === undefined ? noop : _options$complete,
_options$option = options.option,
option = _options$option === undefined ? {} : _options$option;
var isMockDev = G.location.hostname.indexOf('mock.') > -1;
special.duration = special.duration || 4000;
dataType = DATATYPES.indexOf(dataType) > -1 ? dataType : 'text';
url = absUrl(url);
method = method.toUpperCase();
var needUrl2Params = method === 'GET' || method === 'HEAD' || method === 'DELETE';
var baseHeaders = { accept: 'application/json' };
var mixHeaders = _extends({}, baseHeaders, method === 'POST' || method === 'PUT' || method === 'PATCH' ? { 'content-type': 'application/json; charset=UTF-8' } : {}, defaultHeaders, headers);
var isFormData = data instanceof FormData;
if (isFormData) {
delete mixHeaders['content-type']; // /form-urlencoded|form-data/ 'multipart/form-data';
}
var body = isFormData ? needUrl2Params ? formDataFormat(data) : data : data;
if (needUrl2Params) {
// GET 方式问题修复 data中含有undefined值的字段会传给后端,所以数据要转换一下过滤undefined值情况
url += (url.indexOf('?') > 0 ? '&' : '?') + queryString(body);
url = url.replace(/(?:\?|\&)$/, '');
body = null;
} else {
body = typeof body === 'string' || isFormData ? body : JSON.stringify(formDataFormat(body));
}
var response = void 0;
beforeSend();
if (url.indexOf('//mocks.') > -1) {
isMockDev = true;
}
var isHasCover = special.cover === true || isType(special.cover, 'undefined') && webConfig.hasFetchLoading === true;
if (isHasCover) {
protectedLayer('begin');
}
// 兼容那些不支持 AbortController 的浏览器, 备注:IE浏览器不支持 AbortController 不要传 signal
if (!hasSupperAbort) {
G.AbortController = function () {
this.signal = 'error';
this.abort = function () {};
};
}
var abortCtl = new AbortController();
var final = [url, Object.assign({
method: method,
headers: isMockDev ? {} : special.noHeaders ? headers : mixHeaders,
signal: abortCtl.signal,
credentials: 'omit',
// 防止有缓存, 尤其是像IE11用的是polyfill 会有严重缓存问题
cache: 'no-cache',
body: body
}, defaultFetchOptions, option)];
// IE11 会报错处理
if (!hasSupperAbort) {
delete final[1].signal;
}
if (isType(injectBeforeSend, 'function')) {
injectBeforeSend(final);
}
var fetchRes = fetch(new (Function.prototype.bind.apply(Request, [null].concat(final)))()).then(function (res) {
response = res;
// 404 500状态处理
if (res.ok === false) {
throw new Error(res.status == 404 ? '系统网络异常,请稍后再试' : '系统繁忙,请稍后再试');
}
return res[dataType]();
}).then(function (res) {
// 业务事务处理
if (typeof injectResponseCallback === 'function') {
injectResponseCallback({
resModel: res,
options: options,
response: response,
alertMsg: alertMsg,
errMsg: dealErrMsg(res.message || res.msg) || '系统繁忙,请稍后再试!'
});
}
return res;
}).then(function (res) {
var activeData = $ajax.bodyField ? res[$ajax.bodyField] : res;
success(activeData, res, response);
return isType(res) !== 'Object' && isType(res) !== 'Array' || special.intactModel === true ? res : activeData;
}, function (err) {
// 业务事务处理
if (typeof injectResponseErrorCallback === 'function') {
injectResponseErrorCallback({ err: err, options: options, alertMsg: alertMsg, response: response });
}
error(err, response);
console.warn('获取接口数据产生异常:', err && err.message);
}).finally(function (res) {
if (isHasCover) {
protectedLayer('done');
}
complete(res);
return res;
});
if (hasSupperAbort) {
fetchRes.abort = abortCtl.abort.bind(abortCtl);
}
return fetchRes;
};
/**
* 如果有一些自定义提示框 想获取整个response数据情况最好走ajax方法
* @param {object} options - 参数对象
*/
var $ajax = function $ajax(options) {
return request(options);
};
/**
* 设置接口主域名
* @param {string} ajaxBaseUrl - 接口域名
* @param {object} alone - 某些特殊的后端服务 单独配置
*
* @api public
*/
$ajax.setBaseUrl = function (ajaxBaseUrl, alone) {
var cacheBaseUrl = G.localStorage.getItem('ajaxBaseUrl');
var cacheAloneBaseUrl = JSON.parse(G.localStorage.getItem('ajaxAloneBaseUrl')) || alone;
ajaxBaseUrl = cacheBaseUrl || ajaxBaseUrl;
if (ajaxBaseUrl && typeof ajaxBaseUrl === 'string') {
baseUrl = ajaxBaseUrl.indexOf('//') === -1 ? '//' + ajaxBaseUrl : ajaxBaseUrl;
}
if (isType(cacheAloneBaseUrl, 'array') && cacheAloneBaseUrl.length) {
aloneBaseUrl = cacheAloneBaseUrl;
}
};
/**
* fetch方法一些配置及属性设置
* @param {string} key - 字段名称
* @param {any} value - 字段对应的值
* @param {any} value2 - 字段对应的值
*
* @api public
*/
$ajax.set = function (key, value, value2) {
_common2.default.seek()
/**
* 设置baseUrl
*/
.equal(key === 'setBaseUrl', function () {
$ajax.setBaseUrl(value, value2);
})
/**
* 设置接口中是否可带cookie
*/
.equal(key === 'credentials', function () {
defaultFetchOptions.credentials = value;
})
/**
* 重置fetch默认配置参数对象
*/
.equal(key === 'fetchOptions', function () {
defaultFetchOptions = value;
})
/**
* 设置接口主体字段
*/
.equal(key === 'bodyField', function () {
$ajax.bodyField = value;
})
/**
* else
*/
.else(function () {})
/**
* 调用并设置值
*/
.get()();
};
/**
* 获取接口主域名
* @param {boolean} [earnest] - 是否采用自动检测取host方法
*/
$ajax.getBaseUrl = function () {
var earnest = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
return earnest ? baseUrl || location.protocol + '//' + location.host : baseUrl;
};
/**
* 接口请求之前最后的拦截器
* @param {function} callback - 接口请求之前公共拦截器
*/
$ajax.injectBeforeSend = function (callback) {
if (isType(callback, 'function')) {
injectBeforeSend = callback;
}
};
/**
* 注入项目公用headers
* @param {object} headers - 注入接口请求报文header
*/
$ajax.injectHeaders = function (headers) {
if (isType(headers, 'object')) {
defaultHeaders = Object.assign({}, defaultHeaders, headers);
}
};
$ajax.uninjectHeaders = function () {
defaultHeaders = {};
};
/**
* 注入共性事务处理方法 偏业务类型
* @param {function} callback - 回调事务处理
*/
$ajax.injectResponse = function (callback, errorCallback) {
if (typeof callback === 'function') {
injectResponseCallback = callback;
}
if (typeof errorCallback === 'function') {
injectResponseErrorCallback = errorCallback;
}
};
$ajax.appendStyle = addStyles;
/**
* 提供内部某些常用的辅助方法
*/
$ajax.querystring = queryString;
/**
* 加载远程CSS,JS资源文件
* @param {string | array} attachSrc - js或者css服务端或cdn远程地址
* @param {function} cb - 加载成功之后回调
* @param {boolean} remove - 是否移除
*/
var $getScript = function $getScript(attachSrc) {
var cb = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : noop;
var remove = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
var loadCount = 0;
var doc = G.document;
var ohead = doc.documentElement.firstElementChild || doc.getElementsByTagName('head')[0];
var inspect = function inspect(type, src) {
// 不考虑低版本浏览 提高性能就不用for循环了
return doc.querySelector(type === 'script' ? 'script[src="' + src + '"]' : 'link[href="' + src + '"]') === null;
};
var addAttach = function addAttach(src, _ref) {
var resolve = _ref.resolve,
reject = _ref.reject;
var extname = _common2.default.getRequest(src).extname;
var type = /\.js$|\.js\?/.test(src) || extname === 'js' ? 'script' : /\.css$|\.css\?/.test(src) || extname === 'css' ? 'link' : null;
if (!type) {
throw new Error('请传入js或者css地址');
}
if ($getScript.debug && !inspect(type, src)) {
console.log('已经检测到之前有添加过该文件', type, src);
return false;
}
var os = doc.createElement(type);
os.onload = function () {
loadCount++;
if (Array.isArray(attachSrc) && attachSrc.length === loadCount || typeof attachSrc === 'string') {
resolve();
cb();
}
remove === true && type === 'script' && ohead.removeChild(os);
};
os.onerror = function (err) {
reject(err);
};
if (type === 'script') {
os.async = true;
os.src = src;
ohead.appendChild(os);
} else {
os.setAttribute('rel', 'stylesheet');
os.href = src;
ohead.insertBefore(os, ohead.getElementsByTagName('title')[0]);
}
};
return new Promise(function (resolve, reject) {
if (Array.isArray(attachSrc)) {
attachSrc.forEach(function (srcUrl) {
addAttach(srcUrl, { resolve: resolve, reject: reject });
});
} else if (typeof attachSrc === 'string') {
addAttach(attachSrc, { resolve: resolve, reject: reject });
} else {
throw new Error('传入的参数类型不正确!');
}
});
};
/**
* 将对象format成为url中参数格式
* @param {object} params - 对象
*
* @api private
*/
function queryString(params) {
params = _common2.default.clone(params);
Object.keys(params).forEach(function (item) {
if (_common2.default.isType(params[item], 'array') || _common2.default.isType(params[item], 'object')) {
params[item] = JSON.stringify(params[item]);
}
});
if (G.URLSearchParams) {
return new G.URLSearchParams(params).toString();
}
var result = '';
var encode = function encode(v) {
return typeof v === 'string' ? v.replace(/\&/gm, '%26').replace(/\?/gm, '%3F') : v;
};
Object.keys(params).forEach(function (v) {
result += '&' + v + '=' + encode(params[v]);
});
return result.slice(1);
}
/**
* FormData 格式化处理
*/
function formDataFormat(data) {
if (isType(data, 'formData')) {
var result = {};
data.forEach(function (v, k) {
result[k] = v;
});
return result;
}
return data;
}
/**
* 弹框提示
* @api private
*/
var alertMsg = function alertMsg(type, msg, duration) {
var cb = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : noop;
// type 1, 2
var popup = G.document.getElementById(type === 1 ? 'fetch-msg-tip' : 'fetch-err-tip');
var callfn = function callfn() {
if (popup) {
var delay = 0;
if (type === 2) {
popup.className = popup.className.replace('bounce', 'zoomOut');
delay = 820;
}
setTimeout(function () {
if (popup) {
G.document.body.removeChild(popup);
popup = null;
}
}, delay);
}
cb();
};
if (!popup) {
popup = G.document.createElement('div');
popup.id = type === 1 ? 'fetch-msg-tip' : 'fetch-err-tip';
G.document.body.appendChild(popup);
if (type === 1) {
popup.innerHTML = '<div class="popup-box"><div class="dialog-title">\u7CFB\u7EDF\u6E29\u99A8\u63D0\u793A</div><div class="dialog-content">' + msg + '</div><div class="dialog-handler"><button onclick="document.getElementById(\'fetch-msg-tip\').ecb()">\u786E\u5B9A</button></div></div>';
} else {
popup.className = (popup.className || '') + 'animate__animated animate__bounce';
popup.innerHTML = '<div class="popup-box"><div class="dialog-title"><a href="javascript:;" class="close-btn" onclick="document.getElementById(\'fetch-err-tip\').ecb()">×</a></div><div class="dialog-content"><i class="icon-shibai"><svg viewBox="64 64 896 896" focusable="false" class="" data-icon="exclamation-circle" width="35px" height="35px" fill="#f1993b" aria-hidden="true"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"></path><path d="M464 688a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm24-112h48c4.4 0 8-3.6 8-8V296c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8z"></path></svg></i><div class="content-text">' + msg + '</div></div></div>';
// popup.style.width = Math.min(popup.querySelector('.content-text').offsetWidth+90,234+90)+'px';
popup.style.height = Math.max(popup.querySelector('.dialog-content').offsetHeight + 38, 75) + 'px';
duration > 0 && setTimeout(function () {
callfn();
}, 4000); // 自动关闭
}
popup.ecb = callfn;
} else {
var msgTipPop = G.document.querySelector('#fetch-msg-tip .dialog-content');
if (msgTipPop) {
msgTipPop.innerHTML = msg;
popup.ecb = callfn;
}
}
};
// 对error message各种错误格式的兼容处理
var dealErrMsg = function dealErrMsg(msg) {
if (!msg) {
return msg;
}
if (typeof msg === 'string' && msg.indexOf('[') === 0 && msg.lastIndexOf(']') === msg.length - 1) {
try {
msg = JSON.parse(msg);
} catch (er) {}
}
if (Array.isArray(msg)) {
if (isType(msg[0], 'string') && msg[0].indexOf('{') === 0 && msg[0].lastIndexOf('}') === msg[0].length - 1) {
msg = msg.map(function (err) {
return JSON.parse(err);
});
}
if (isType(msg[0], 'object') && msg[0].value) {
msg = msg.map(function (err, index) {
return msg.length === 1 ? err.value : index + 1 + '\u3001' + err.value;
}).join(' ');
} else {
msg = msg.map(function (err, index) {
return msg.length === 1 ? err : index + 1 + '\u3001' + err;
}).join(' ');
}
}
return msg;
};
// 数据请求之前 加蒙板处理
var protectedLayerTimer1 = null;
var protectedLayerTimer2 = null;
var protectedLayer = function protectedLayer(actionType) {
fetchingCount = fetchingCount || 0;
var addCover = function addCover() {
if (coverElement) {
return false;
}
coverElement = G.document.createElement('div');
coverElement.id = 'fetch-loading-cover';
if (!G.document.getElementById('fetch-loading-cover')) {
G.document.body.appendChild(coverElement);
}
clearTimeout(protectedLayerTimer1);
protectedLayerTimer1 = setTimeout(function () {
if (coverElement) {
coverElement.className = (coverElement.className || '') + 'runAnt';
}
}, 500);
};
var removeCover = function removeCover() {
if (fetchingCount < 1 && coverElement) {
coverElement.className = '';
clearTimeout(protectedLayerTimer2);
protectedLayerTimer2 = setTimeout(function () {
if (fetchingCount < 1 && coverElement && G.document.getElementById('fetch-loading-cover')) {
G.document.body.removeChild(coverElement);
coverElement = null;
}
}, 700);
}
};
if (actionType === 'begin') {
fetchingCount++;
addCover();
} else if (actionType === 'done') {
fetchingCount--;
removeCover();
}
};
exports.default = $ajax;
/**
* 接口GET调用方式
* @param {string} url - 接口地址
* @param {object} params - 接口参数
* @param {function} callback - 接口调用成功回调
* @param {string} dataType - 响应数据类型
*/
var $get = exports.$get = function $get(url, params, callback, dataType) {
if (isType(params, 'function')) {
callback = params;params = {};
}
if (isType(params, 'string') && DATATYPES.indexOf(params) > -1) {
dataType = params;params = {};
}
if (isType(callback, 'string') && DATATYPES.indexOf(callback) > -1) {
dataType = callback;callback = undefined;
}
return request({ url: url, data: params, dataType: dataType, success: callback });
};
/**
* 接口DELETE调用方式
* @param {string} url - 接口地址
* @param {object} params - 接口参数
* @param {function} callback - 接口调用成功回调
* @param {string} dataType - 响应数据类型
*/
var $delete = exports.$delete = function $delete(url, params, callback, dataType) {
if (isType(params, 'function')) {
callback = params;params = {};
}
if (isType(params, 'string') && DATATYPES.indexOf(params) > -1) {
dataType = params;params = {};
}
if (isType(callback, 'string') && DATATYPES.indexOf(callback) > -1) {
dataType = callback;callback = undefined;
}
return request({ url: url, data: params, type: 'delete', dataType: dataType, success: callback });
};
/**
* 接口HEAD调用方式
* @param {string} url - 接口地址
* @param {object} params - 接口参数
* @param {function} callback - 接口调用成功回调
* @param {string} dataType - 响应数据类型
*/
var $head = exports.$head = function $head(url, params, callback, dataType) {
if (isType(params, 'function')) {
callback = params;params = {};
}
if (isType(params, 'string') && DATATYPES.indexOf(params) > -1) {
dataType = params;params = {};
}
if (isType(callback, 'string') && DATATYPES.indexOf(callback) > -1) {
dataType = callback;callback = undefined;
}
return request({ url: url, data: params, type: 'head', dataType: dataType, success: callback });
};
/**
* 接口POST调用方式
* @param {string} url - 接口地址
* @param {object} params - 接口参数
* @param {function} callback - 接口调用成功回调
* @param {string} dataType - 响应数据类型
*/
var $post = exports.$post = function $post(url, params, callback, dataType) {
if (isType(params, 'function')) {
callback = params;params = {};
}
if (isType(params, 'string') && DATATYPES.indexOf(params) > -1) {
dataType = params;params = {};
}
if (isType(callback, 'string') && DATATYPES.indexOf(callback) > -1) {
dataType = callback;callback = undefined;
}
return request({ url: url, data: params, type: 'post', dataType: dataType, success: callback });
};
/**
* 接口PUT调用方式
* @param {string} url - 接口地址
* @param {object} params - 接口参数
* @param {function} callback - 接口调用成功回调
* @param {string} dataType - 响应数据类型
*/
var $put = exports.$put = function $put(url, params, callback, dataType) {
if (isType(params, 'function')) {
callback = params;params = {};
}
if (isType(params, 'string') && DATATYPES.indexOf(params) > -1) {
dataType = params;params = {};
}
if (isType(callback, 'string') && DATATYPES.indexOf(callback) > -1) {
dataType = callback;callback = undefined;
}
return request({ url: url, data: params, type: 'put', dataType: dataType, success: callback });
};
/**
* 接口PATCH调用方式
* @param {string} url - 接口地址
* @param {object} params - 接口参数
* @param {function} callback - 接口调用成功回调
* @param {string} dataType - 响应数据类型
*/
var $patch = exports.$patch = function $patch(url, params, callback, dataType) {
if (isType(params, 'function')) {
callback = params;params = {};
}
if (isType(params, 'string') && DATATYPES.indexOf(params) > -1) {
dataType = params;params = {};
}
if (isType(callback, 'string') && DATATYPES.indexOf(callback) > -1) {
dataType = callback;callback = undefined;
}
return request({ url: url, data: params, type: 'patch', dataType: dataType, success: callback });
};
/**
* jsonp实现方案
* @param {string} url - 接口地址
* @param {object} [params] - 接口参数
* @param {string} [callbackName="callback"] - callback名称,一般情况下不需要特定,用默认值即可
*/
var $jsonp = exports.$jsonp = function $jsonp(url) {
var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var callbackName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'callback';
var cbName = 'tsh_call_' + Date.now().toString(32);
var resModel = void 0;
G[cbName] = function (data) {
resModel = data;
};
params.extname = 'js';
params[callbackName] = cbName;
return $getScript(_common2.default.concatSearch(url, params)).then(function () {
delete G[cbName];
return resModel;
}, function (er) {
delete G[cbName];
return er;
});
};
exports.$getScript = $getScript;
function absUrl(url) {
if (url.indexOf('//') === -1) {
var chost = Array.isArray(aloneBaseUrl) && aloneBaseUrl.find(function (item) {
var reg = new RegExp(item.test);
return reg.test(url);
});
if (chost) {
url = chost.host + url;
} else if (baseUrl) {
url = baseUrl + url;
} else {
url = location.origin + url;
}
}
return url;
}
function addStyles(colors) {
if (!document.getElementById('fetch-styles')) {
var title = document.getElementsByTagName('title');
_common2.default.appendStyle((0, _style2.default)(colors), { id: 'fetch-styles', before: title[0] });
}
}
(0, _orderly2.default)(function () {
addStyles();
}, { sleep: 80, type: 'debounce' })();