/*!
* cloud-utils v1.0.0
* API
* Copyright 2017-2020 windraxb. All Rights Reserved
* Licensed under MIT
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
/**
*
* @param {number} arg1
* @param {number} arg2
* @returns {number} arg1加上arg2的精确结果
* @example
*
* accAdd(0.1, 0.2)
* // => 0.3
*/
function accAdd (arg1, arg2) {
var r1;
var r2;
var m;
try {
r1 = arg1.toString().split('.')[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = arg2.toString().split('.')[1].length;
} catch (e) {
r2 = 0;
}
var c = Math.abs(r1 - r2);
m = Math.pow(10, Math.max(r1, r2));
if (c > 0) {
var cm = Math.pow(10, c);
if (r1 > r2) {
arg1 = Number(arg1.toString().replace('.', ''));
arg2 = Number(arg2.toString().replace('.', '')) * cm;
} else {
arg1 = Number(arg1.toString().replace('.', '')) * cm;
arg2 = Number(arg2.toString().replace('.', ''));
}
} else {
arg1 = Number(arg1.toString().replace('.', ''));
arg2 = Number(arg2.toString().replace('.', ''));
}
return (arg1 + arg2) / m
}
/**
* 除法函数,用来得到精确的除法结果<br>
* javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。
*
* @param {number} arg1
* @param {number} arg2
* @returns {number} arg1除以arg2的精确结果
* @example
*
* accDiv(0.2, 0.3)
* // => 0.6666666666666666
*/
function accDiv (arg1, arg2) {
var t1 = 0;
var t2 = 0;
var r1, r2;
if (+arg2 === 0) {
throw new Error('0 is not allowed for divisor')
}
try {
arg1.toString().split('.')[1] && (t1 += arg1.toString().split('.')[1].length);
} catch (e) {
console.error(e);
}
try {
arg2.toString().split('.')[1] && (t2 += arg2.toString().split('.')[1].length);
} catch (e) {
console.error(e);
}
r1 = Number(arg1.toString().replace('.', ''));
r2 = Number(arg2.toString().replace('.', ''));
return (r1 / r2) * Math.pow(10, t2 - t1)
}
/**
* 乘法函数,用来得到精确的乘法结果<br>
* javascript的乘法结果会由误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果
*
* @param {number} arg1
* @param {number} arg2
* @returns {number} arg1乘arg2的精确结果
* @example
*
* accMul(0.222, 0.3333)
* // => 0.0739926
*/
function accMul (arg1, arg2) {
var m = 0;
var s1 = arg1.toString();
var s2 = arg2.toString();
try {
s1.split('.')[1] && (m += s1.split('.')[1].length);
} catch (e) {
console.error(e);
}
try {
s2.split('.')[1] && (m += s2.split('.')[1].length);
} catch (e) {
console.error(e);
}
return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m)
}
/**
* 减法函数,用来得到精确的减法结果<br>
* javascript的减法结果会有误差,在两个浮点数相减的时候会比较明显。这个函数返回较为精确的减法结果。
*
* @param {number} arg1
* @param {number} arg2
* @returns {number} arg1减去arg2的精确结果
* @example
*
* accSub(0.3, 0.2)
* // => 0.1
*/
function accSub (arg1, arg2) {
var r1 = 0;
var r2 = 0;
var m;
var n;
try {
arg1.toString().split('.')[1] && (r1 = arg1.toString().split('.')[1].length);
} catch (e) {
console.error(e);
}
try {
arg2.toString().split('.')[1] && (r2 = arg2.toString().split('.')[1].length);
} catch (e) {
console.error(e);
}
m = Math.pow(10, Math.max(r1, r2));
n = Math.max(r1, r2);
return ((arg1 * m - arg2 * m) / m).toFixed(n)
}
/**
* 为数字加上单位:万或亿
* @param {number} number 输入数字.
* @param {number} decimalDigit 返回的小数点后最多的位数,默认为 2
* @returns {string | *} 加上单位后的数字
*
* @example
* addChineseUnit(1000.01)
* // => 1000.01
*
* addChineseUnit(10000)
* // => 1万
*
* addChineseUnit(99000)
* // => 9.9万
*
* addChineseUnit(566000)
* // => 56.6万
*
* addChineseUnit(5660000)
* // => 566万
*
* addChineseUnit(44440000)
* // => 4444万
*
* addChineseUnit(11111000)
* // => 1111.1万
*
* addChineseUnit(444400000)
* // => 4.44亿
*
* addChineseUnit(400000000000000000000000)
* // => 3999.99万亿亿
*
* addChineseUnit(4000000000000000000000000)
* // => 4亿亿亿
*/
function addChineseUnit (number, decimalDigit) {
var addWan = function (integer, number, mutiple, decimalDigit) {
var digit = getDigit(integer);
if (digit > 3) {
var remainder = digit % 8;
remainder = remainder >= 5 ? 4 : remainder;
return Math.round(number / Math.pow(10, remainder + mutiple - decimalDigit)) / Math.pow(10, decimalDigit) + '万'
} else {
return Math.round(number / Math.pow(10, mutiple - decimalDigit)) / Math.pow(10, decimalDigit)
}
};
var getDigit = function (integer) {
integer = Math.abs(integer);
var digit = -1;
while (integer >= 1) {
digit++;
integer = integer / 10;
}
return digit
};
return (function (number, decimalDigit) {
decimalDigit = decimalDigit == null ? 2 : decimalDigit;
var integer = Math.floor(number);
var digit = getDigit(integer);
var unit = [];
if (digit > 3) {
var multiple = Math.floor(digit / 8);
if (multiple >= 1) {
var tmp = Math.round(integer / Math.pow(10, 8 * multiple));
unit.push(addWan(tmp, number, 8 * multiple, decimalDigit));
for (var i = 0; i < multiple; i++) {
unit.push('亿');
}
return unit.join('')
} else {
return addWan(integer, number, 0, decimalDigit)
}
} else {
return parseFloat(number).toFixed(decimalDigit)
}
}(number, decimalDigit))
}
/**
* 加密算法
* 1.所有入参加入集合M,参数名做key, 值做value
* 2.提供的密钥1(字段名appid)与密钥2(字段名secret)两项,以及当前时间戳(字段名time)也加入集合M,
* 3.将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序)
* 4.集合M所有值拼接成字符串,转化成UTF-8编码格式的字节数组, 最后需要取MD5码(signature摘要值)
*
* @param {object} params
* @example
*
* const params = { mobile: '15858264900', nickname: 'windraxb', appkey: 'ertfgdf345435568123454rtoiko5=' };
*
* md5(encrypt(params).toUpperCase());
* // => md5('APPKEY=ERTFGDF34543545=&MOBILE=15858264903&NICKNAME=windraxb')
*/
function encrypt (params) {
// 顺序排列key
var keys = Object.keys(params).sort();
var str = [];
keys.forEach(function (p) {
str.push(p + '=' + params[p]);
});
return str.join('&')
}
/**
* 格式化银行卡<br>
* 用户在输入银行卡号时,需要以4位4位的形式显示,就是每隔4位加个空格,方便用户校对输入的银行卡是否正确<br>
* **注:**一般数据库里面存的都是不带格式的原始数据,所以提交的时候记得过滤下空格再提交哦。毕竟格式化这种算是表现层,前端展示的时候处理下就好,业务逻辑什么用到的卡号可不是格式化后的呢。<br>
* 还原`val.replace(/\s/g, '');`
*
* @param {string} val
* @returns {*}
* @example
*
* formatBankCard('6225365271562822');
* // => 6225 3652 7156 2822
*/
function formatBankCard (val) {
if (typeof val !== 'string') { throw new Error('输入值必须为字符串') }
var len = val.length;
var reg = /(\d{4})(?=\d)/g;
if (len < 4) {
return val
} else {
return val.replace(reg, '$1 ')
}
}
/**
* Date 转化为指定格式的String<br>
* 月(M)、日(d)、12小时(h)、24小时(H)、分(m)、秒(s)、周(E)、季度(q)可以用 1-2 个占位符<br>
* 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
*
* @param {string | number} date string支持形式:20160126 12:00:00,2016-01-26 12:00:00,2016.01.26 12:00:00,20160126,2016-01-26 12:00:00.0
* @param {string} fmt
* @returns {string}
* @example
*
* formatDate(Date.now(), 'yyyy-MM-dd hh:mm:ss.S');
* // => 2006-07-02 08:09:04.423
*
* formatDate(Date.now(), 'yyyy-MM-dd E HH:mm:ss');
* // => 2009-03-10 二 20:09:04
*
* formatDate(Date.now(), 'yyyy-MM-dd EE hh:mm:ss');
* // => 2009-03-10 周二 08:09:04
*
* formatDate(Date.now(), 'yyyy-MM-dd EEE hh:mm:ss');
* // => 2009-03-10 星期二 08:09:04
*
* formatDate(Date.now(), 'yyyy-M-d h:m:s.S')
* // => 2006-7-2 8:9:4.18
*/
function formatDate (date, fmt) {
if ( date === void 0 ) date = new Date();
if ( fmt === void 0 ) fmt = 'yyyy-MM-dd HH:mm:ss';
if (typeof date === 'string') {
date = new Date(formatTimeByPattern(date));
} else if (typeof date === 'number') {
date = new Date(date);
}
var o = {
'M+': date.getMonth() + 1, // 月份
'd+': date.getDate(), // 日
'h+': date.getHours() % 12 === 0 ? 12 : date.getHours() % 12, // 小时
'H+': date.getHours(), // 小时
'm+': date.getMinutes(), // 分
's+': date.getSeconds(), // 秒
'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
S: date.getMilliseconds() // 毫秒
};
var week = {
0: '\u65e5',
1: '\u4e00',
2: '\u4e8c',
3: '\u4e09',
4: '\u56db',
5: '\u4e94',
6: '\u516d'
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
}
if (/(E+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? '\u661f\u671f' : '\u5468') : '') + week[date.getDay() + '']);
}
for (var k in o) {
if (new RegExp('(' + k + ')').test(fmt)) {
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
}
}
return fmt
}
// val 字符串转换成 / 连接
// 20160126 12:00:00
// 2016-01-26 12:00:00
// 2016.01.26 12:00:00
// 20160126
// 2016-01-26 12:00:00.0
function formatTimeByPattern (val) {
// 2016-05-23 13:58:02.0
if (val.length > 19) {
val = val.substring(0, 19);
}
var pattern = /-|\./g;
var year;
var month;
var day;
var reset;
if (pattern.test(val)) {
return val.replace(pattern, '/')
} else {
// 若无’-‘,则不处理
if (!~val.indexOf('-')) {
year = val.slice(0, 4);
month = val.slice(4, 6);
day = val.slice(6, 8);
reset = val.slice(8);
return year + '/' + month + '/' + day + reset
}
}
}
/**
* 将时间转化为几天前,几小时前,几分钟前
*
* @param {number} ms
* @returns {*}
* @example
*
* formatTimeAgo(1505232000000);
* // => 1天前
*/
function formatTimeAgo (ms) {
ms = parseInt(ms);
var timeNow = Date.now();
var diff = (timeNow - ms) / 1000;
var date = new Date();
var days = Math.round(diff / (24 * 60 * 60));
var hours = Math.round(diff / (60 * 60));
var minutes = Math.round(diff / 60);
var second = Math.round(diff);
if (days > 0 && days < 2) {
return days + '天前'
} else if (days <= 0 && hours > 0) {
return hours + '小时前'
} else if (hours <= 0 && minutes > 0) {
return minutes + '分钟前'
} else if (minutes <= 0 && second >= 0) {
return '刚刚'
} else {
date.setTime(ms);
return (date.getFullYear() + '-' + f(date.getMonth() + 1) + '-' + f(date.getDate()) + ' ' + f(date.getHours()) + ':' + f(date.getMinutes()))
}
function f (n) {
return (n < 10) ? '0' + n : n
}
}
/**
* 获取指定时间unix时间戳
*
* @param {string} time
* @returns {number}
* @example
*
* formatDateToTimeStamp('20160126 12:00:00');
* // => 1453780800000
*
* formatDateToTimeStamp('2016-01-26 12:00:00');
* // => 1453780800000
*
* formatDateToTimeStamp('2016.01.26 12:00:00');
* // => 1453780800000
*
* formatDateToTimeStamp('20160126');
* // => 1453737600000
*
* formatDateToTimeStamp('2016-01-26 12:00:00.0');
* // => 1453780800000
*/
function formatDateToTimeStamp (time) {
if (typeof time !== 'string') { throw new TypeError('数据类型必须是 string') }
// 2016-05-23 13:58:02.0
if (time.length > 19) {
time = time.substring(0, 19);
}
var unixTime;
var pattern = /-|\./g;
var year;
var month;
var day;
var reset;
if (pattern.test(time)) {
unixTime = time.replace(pattern, '/');
} else {
// 若无’-‘,则不处理
if (!~time.indexOf('-')) {
year = time.slice(0, 4);
month = time.slice(4, 6);
day = time.slice(6, 8);
reset = time.slice(8);
unixTime = year + '/' + month + '/' + day + reset;
}
}
return Math.round(new Date(unixTime).getTime())
}
/**
* 用符号(默认为逗号)格式化金钱
*
* @param {string} val
* @param {string} symbol 默认`,`
* @returns {string|*|XML|void}
* @example
*
* formatMoney('1234567890');
* // => 1,234,567,890
*/
function formatMoney (val, symbol) {
if ( symbol === void 0 ) symbol = ',';
if (typeof val !== 'string') { throw new TypeError('数据类型必须是 string') }
return val.replace(/\B(?=(\d{3})+(?!\d))/g, symbol)
}
/**
* 手机号码中间部分替换成指定符号
*
* @param {string} phone
* @param {string} symbol 默认为`*`
* @returns {string|*|XML|void}
* @example
*
* formatPhone('15858264903');
* // => 158****4903
*/
function formatPhone (phone, symbol) {
if ( symbol === void 0 ) symbol = '****';
if (typeof phone !== 'string') { throw new TypeError('数据类型必须是 string') }
return phone.replace(/(\d{3})\d{4}(\d{4})/, ("$1" + symbol + "$2"))
}
/**
* 获取location.href参数
*
* @param {string} name
* @returns {*}
* @example
*
* window.location.href = 'http://www.baidu.com/?a=1&b=2';
*
* getLocationHrefParam('a');
* // => 1
*/
function getLocationHrefParam (name) {
// 构造一个含有目标参数的正则表达式对象
var r = new RegExp('(\\?|#|&)' + name + '=([^&#]*)(&|#|$)');
var m = window.location.href.match(r);
if (r !== null) { return decodeURIComponent(!m ? '' : m[2]) }
return null
}
/**
* 获取location.search的参数
*
* @param {string} name
* @returns {*}
* @example
*
* window.location.href = 'http://www.baidu.com/?a=1&b=2';
*
* getLocationSearchParam('a');
* // => 1
*/
function getLocationSearchParam (name) {
// 构造一个含有目标参数的正则表达式对象
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)');
// 匹配目标参数
var r = window.location.search.substr(1).match(reg);
if (r !== null) { return decodeURIComponent(r[2]) }
return null
}
/**
* html字符解码
*
* @param {string} str
* @returns {string}
* @example
*
* htmlDecode('<script>');
* // => <script>
*/
function htmlDecode (str) {
if (typeof str === 'string' && str.length === 0) { return }
var s = str.replace(/&/g, '&');
return s.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/'/g, '\'')
.replace(/ /g, ' ')
.replace(/"/g, '"')
.replace(/<br>/g, '\\n')
}
/**
* html字符编码
*
* @param {string} str
* @returns {string}
* @example
*
* htmlEncode('<script>');
* // => <script>
*/
function htmlEncode (str) {
if (typeof str === 'string' && str.length === 0) { return }
var s = str.replace(/&/g, '&');
return s.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/'/g, ''')
.replace(/ /g, ' ')
.replace(/"/g, '"')
.replace(/\n/g, '<br>')
}
/**
* 是否是支付宝内核
*
* @returns {boolean}
* @example
*
* inAlipay();
* // => false
*/
function inAlipay () {
if (typeof navigator === 'undefined') { return }
var ua = navigator.userAgent.toLowerCase();
return ua.indexOf('alipayclient') !== -1
}
/**
* 是否是微信内核
*
* @returns {boolean}
* @example
*
* inWeixin();
* // => false
*/
function inWeixin () {
if (typeof navigator === 'undefined') { return }
var ua = navigator.userAgent.toLowerCase();
return ua.indexOf('micromessenger') !== -1
}
/**
* 是否为有效的身份证号,支持1/2代(15位/18位数字)
*
* @param {string} val
* @returns {boolean}
* @example
*
* isCardId('411423198807127834');
* // => true
*/
function isCardId (val) {
var reg = /(^\d{8}(0\d|10|11|12)([0-2]\d|30|31)\d{3}$)|(^\d{6}(18|19|20)\d{2}(0\d|10|11|12)([0-2]\d|30|31)\d{3}(\d|X|x)$)/;
return reg.test(val)
}
/**
* 是否为数字
*
* @param {string} val
* @returns {boolean}
* @example
*
* isDigit('abc');
* // => false
*/
function isDigit (val) {
var reg = /^-?\d+\.?\d*$/;
return reg.test(val)
}
/**
* 是否为空对象
*
* @param val
* @returns {boolean}
* @example
*
* isEmptyObject({});
* // => true
*/
function isEmptyObject (val) {
if (val !== Object(val)) { return false }
return Object.keys(val).length === 0
}
/**
* 是否为闰年
*
* @param {number} val
* @returns {boolean}
* @example
*
* isLeapYear(2000);
* // => true
*/
function isLeapYear (val) {
if (typeof val !== 'number') { throw new TypeError('数据类型必须是 number') }
if (val % 4 === 0 && val % 100 !== 0) {
return true
} else {
return val % 400 === 0
}
}
/**
* 是否为字母
*
* @param {string} val
* @returns {boolean}
* @example
*
* isLetters('1234');
* // => false
*/
function isLetters (val) {
var reg = /^[a-z]+$/i;
return reg.test(val)
}
/**
* 是否为有效的邮箱地址<br>
* 名称允许汉字、字母、数字,域名只允许英文域名<br>
* 中文如:杨元庆001Abc@lenovo.com.cn
*
* @param {string} val
* @returns {boolean}
* @example
*
* isValidEmail('123456@qq.com');
* // => true
*/
function isValidEmail (val) {
var reg = /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/i;
return reg.test(val)
}
/**
* 对整数进行前置补0
*
* @param {number} num 数值
* @param {number} size 要补0的位数
* @returns {string}
* @example
*
* preZeroFill(12, 3);
* // => 012
*/
function preZeroFill (num, size) {
if (num >= Math.pow(10, size)) {
return num.toString()
} else {
var _str = Array(size + 1).join('0') + num;
return _str.slice(_str.length - size)
}
}
/**
* 字节转换为B,KB,MB
* @param {Number} bytes
* @returns {string}
* @example
*
* bytesToSize(10000)
* // => 9.8 KB
*/
function bytesToSize (bytes) {
var sizes = ['B', 'KB', 'MB'];
if (bytes === 0) { return 'n/a' }
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]
}
/**
* base64转blob
*
* @param {string} dataURL
* @returns {*}
* @example
*
* const URI = 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj48ZGVmcz48c3R5bGUvPjwvZGVmcz48cGF0aCBkPSJNOTU5LjQzNiAyNDMuNUwzNzcuNDEzIDg3MC4yNyA2NC4wMiA0NjcuMzQ0bDExNC43MjctOTcuOTMgMTk4LjY2NiAyMDcuMDYgNDkyLjQ4Mi00MjIuNTEgODkuNTQgODkuNTM3em0wIDAiIGZpbGw9IiM0M2E5ZjEiLz48L3N2Zz4=';
*
* dataURLToBlob(URI);
* // => Blob {size: 248, type: "image/svg+xml"}
*/
function dataURLToBlob (dataURL) {
var BASE64_MARKER = ';base64,';
var parts;
var contentType;
var raw;
if (dataURL.indexOf(BASE64_MARKER) === -1) {
parts = dataURL.split(',');
contentType = parts[0].split(':')[1];
raw = decodeURIComponent(parts[1]);
return new Blob([raw], { type: contentType })
}
parts = dataURL.split(BASE64_MARKER);
contentType = parts[0].split(':')[1];
raw = window.atob(parts[1]);
var rawLength = raw.length;
var uint8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uint8Array[i] = raw.charCodeAt(i);
}
return new Blob([uint8Array], { type: contentType })
}
/**
* 获取设备像素比
*
* @returns {number}
* @example
*
* // window.navigator.appVersion(5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1)
* getPixelRatio();
* // => 2
*/
function getPixelRatio () {
var ctx = document.createElement('canvas').getContext('2d');
var dpr = window.devicePixelRatio || 1;
var bsr = ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1;
return dpr / bsr
}
/**
* 获取移动设备信息,如是否是iOS,android等
*
* @returns {{}}
* @example
*
* getDevice();
* // => {"androidChrome":false,"ipad":false,"iphone":true,"android":false,"ios":true,"os":"ios","osVersion":"9.1","webView":null}
*/
function getDevice () {
var device = {};
var ua = navigator.userAgent;
var android = ua.match(/(Android);?[\s/]+([\d.]+)?/);
var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/);
var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/);
device.ios = device.android = device.iphone = device.ipad = device.androidChrome = false;
// Android
if (android) {
device.os = 'android';
device.osVersion = android[2];
device.android = true;
device.androidChrome = ua.toLowerCase().indexOf('chrome') >= 0;
}
if (ipad || iphone || ipod) {
device.os = 'ios';
device.ios = true;
}
// iOS
if (iphone && !ipod) {
device.osVersion = iphone[2].replace(/_/g, '.');
device.iphone = true;
}
if (ipad) {
device.osVersion = ipad[2].replace(/_/g, '.');
device.ipad = true;
}
if (ipod) {
device.osVersion = ipod[3] ? ipod[3].replace(/_/g, '.') : null;
device.iphone = true;
}
// iOS 8+ changed UA
if (device.ios && device.osVersion && ua.indexOf('Version/') >= 0) {
if (device.osVersion.split('.')[0] === '10') {
device.osVersion = ua.toLowerCase().split('version/')[1].split(' ')[0];
}
}
// Webview
device.webView = (iphone || ipad || ipod) && ua.match(/.*AppleWebKit(?!.*Safari)/i);
return device
}
/**
* 获取浏览器的类型和版本号
*
* @returns {{type: string, version: string}}
* @example
*
* getBrowser();
* // => {type: "chrome", version: "60.0.3112.101"}
*/
function getBrowser () {
var ua = navigator.userAgent.toLowerCase();
var type = 'UNKNOW';
var v;
var check = function (regex) {
return regex.test(ua)
};
// IE
if (check(/msie/) && !check(/opera/)) {
type = 'ie';
v = /msie[/|\s]*([\d+?.?]+)/.exec(ua);
} else if ((!check(/webkit/) && check(/gecko/) && check(/firefox/)) && !check(/opera/)) { // firefox
type = 'firefox';
v = /firefox[/|\s]*([\d+?.?]+)/.exec(ua);
} else if (check(/\bchrome\b/)) { // chrome
type = 'chrome';
v = /chrome[/|\s]*([\d+?.?]+)/.exec(ua);
} else if (check(/applewebkit/) && check(/safari/)) { // safari (!check(/\bchrome\b/) is ensure by non-chrome above)
type = 'safari';
v = /version[/|\s]*([\d+?.?]+)/.exec(ua);
} else if (check(/opera/)) {
type = 'opera';
v = /version[/|\s]*([\d+?.?]+)/.exec(ua) || /opera[/|\s]*([\d+?.?]+)/.exec(ua);
}
return {
type: type,
version: (v && v[1]) ? v[1] : 'UNKNOW'
}
}
/**
* 得到两个时间的时间差(返回天数)
*
* @param {number} startDay 开始时间戳
* @param {number} endDay 结束时间戳
* @returns {number}
* @example
*
* getDiffDay(1501516800000, 1504195200000);
* // => 31
*/
function getDiffDay (startDay, endDay) {
startDay = Number(startDay);
endDay = Number(endDay);
return Math.abs(endDay - startDay) / (24 * 1000 * 3600)
}
/**
* Dom操作,元素是否包含某个class
* @param el HTML元素
* @param cls class类名
* @returns {boolean}
* @example
*
* <div class="box flex"></div>
* hasClass(document.querySelector('.box'), 'flex');
* // => true
*/
function hasClass (el, cls) {
if (!el || !cls) { return false }
if (cls.indexOf(' ') !== -1) { throw new Error('className should not contain space.') }
if (el.classList) {
return el.classList.contains(cls)
} else {
return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1
}
}
/**
* dom操作,元素添加某个class
* @param el HTML元素
* @param cls class名称
* @example
*
* <div class="box flex"></div>
* addClass(document.querySelector('.box'), 'flex1');
* // => <div class="box flex flex1"></div>
*/
function addClass (el, cls) {
if (!el) { return }
var curClass = el.className;
var classes = (cls || '').split(' ');
for (var i = 0, length = classes.length; i < length; i++) {
var clsName = classes[i];
if (!clsName) { continue }
if (el.classList) {
el.classList.add(clsName);
} else {
if (!hasClass(el, clsName)) {
curClass += ' ' + clsName;
}
}
}
if (!el.classList) {
el.className = curClass;
}
}
var trim = function (string) {
return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '')
};
/**
* Dom 操作,元素删除某个 class
*
* @param el HTML元素
* @param cls css类名
* @example
*
* <div class="box flex"></div>
* removeClass(document.querySelector('.box'), 'flex');
* // => <div class="box"></div>
*/
function removeClass (el, cls) {
if (!el || !cls) { return }
var classes = cls.split(' ');
var curClass = ' ' + el.className + ' ';
for (var i = 0, j = classes.length; i < j; i++) {
var clsName = classes[i];
if (!clsName) { continue }
if (el.classList) {
el.classList.remove(clsName);
} else {
if (hasClass(el, clsName)) {
curClass = curClass.replace(' ' + clsName + ' ', ' ');
}
}
}
if (!el.classList) {
el.className = trim(curClass);
}
}
/**
* 格式化数字、金额、千分位、保留几位小数、舍入舍去
*
* @param number 要格式化的数字
* @param decimals 保留几位小数
* @param decPoint 小数点符号
* @param thousandsSep 千分位符号
* @param roundTag 舍入参数,默认 'ceil' 向上取,'floor'向下取,'round' 四舍五入
* @returns {XML|void|*|string}
* @example
*
* formatNumber(2, 2, '.', ',');
* // => 2.00
*/
function formatNumber (number, decimals, decPoint, thousandsSep, roundTag) {
if ( decimals === void 0 ) decimals = 2;
if ( decPoint === void 0 ) decPoint = '.';
if ( thousandsSep === void 0 ) thousandsSep = ',';
if ( roundTag === void 0 ) roundTag = 'ceil';
number = (number + '').replace(/[^0-9+-Ee.]/g, '');
var n = !isFinite(+number) ? 0 : +number;
var prec = !isFinite(+decimals) ? 0 : Math.abs(decimals);
var sep = thousandsSep || ',';
var dec = decPoint || '.';
var re = /(-?\d+)(\d{3})/;
var s = '';
var toFixedFix = function (n, prec) {
var k = Math.pow(10, prec);
return '' + parseFloat(Math[roundTag](parseFloat((n * k).toFixed(prec * 2))).toFixed(prec * 2)) / k
};
s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
while (re.test(s[0])) {
s[0] = s[0].replace(re, '$1' + sep + '$2');
}
if ((s[1] || '').length < prec) {
s[1] = s[1] || '';
s[1] += new Array(prec - s[1].length + 1).join('0');
}
return s.join(dec)
}
/**
* 版本比较
*
* @param v1 老版本
* @param v2 新版本
* @returns {number} v1 > v2 => 1, v1 < v2 => -1, v1 === v2 => 0
* @example
*
* compareVersion('10.1.8', '10.0.4');
* // => 1
* compareVersion('10.0.1', '10.0.1');
* // => 0
* compareVersion('10.1.1', '10.2.2');
* // => -1
*/
/* eslint-disable */
function compareVersion (v1, v2) {
var semver = /^v?(?:\d+)(\.(?:[x*]|\d+)(\.(?:[x*]|\d+)(\.(?:[x*]|\d+))?(?:-[\da-z\-]+(?:\.[\da-z\-]+)*)?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;
function indexOrEnd (str, q) {
return str.indexOf(q) === -1 ? str.length : str.indexOf(q)
}
function split (v) {
var c = v.replace(/^v/, '').replace(/\+.*$/, '');
var patchIndex = indexOrEnd(c, '-');
var arr = c.substring(0, patchIndex).split('.');
arr.push(c.substring(patchIndex + 1));
return arr
}
function tryParse (v) {
return isNaN(Number(v)) ? v : Number(v)
}
function validate (version) {
if (typeof version !== 'string') {
throw new TypeError('Invalid argument expected string')
}
if (!semver.test(version)) {
throw new Error('Invalid argument not valid semver (\'' + version + '\' received)')
}
}
[v1, v2].forEach(validate);
var s1 = split(v1);
var s2 = split(v2);
for (var i = 0; i < Math.max(s1.length - 1, s2.length - 1); i++) {
var n1 = parseInt(s1[i] || 0, 10);
var n2 = parseInt(s2[i] || 0, 10);
if (n1 > n2) { return 1 }
if (n2 > n1) { return -1 }
}
var sp1 = s1[s1.length - 1];
var sp2 = s2[s2.length - 1];
if (sp1 && sp2) {
var p1 = sp1.split('.').map(tryParse);
var p2 = sp2.split('.').map(tryParse);
for (i = 0; i < Math.max(p1.length, p2.length); i++) {
if (p1[i] === undefined || typeof p2[i] === 'string' && typeof p1[i] === 'number') { return -1 }
if (p2[i] === undefined || typeof p1[i] === 'string' && typeof p2[i] === 'number') { return 1 }
if (p1[i] > p2[i]) { return 1 }
if (p2[i] > p1[i]) { return -1 }
}
} else if (sp1 || sp2) {
return sp1 ? -1 : 1
}
return 0
}
/**
* 主动防御
* 对于我们操作的数据,尤其是由 API 接口返回的,时常会有一个很复杂的深层嵌套的数据结构。为了代码的健壮性,很多时候需要对每一层访问都作空值判断,就像这样:
props.user &&
props.user.posts &&
props.user.posts[0] &&
props.user.posts[0].comments &&
props.user.posts[0].comments[0]
代码看起来相当不美观,因此提供了一个非常简洁明了的原生的方式。
*
* @param p 属性列表
* @param o 对象
* @returns {*} 如果正常访问到,则返回对应的值,否则返回 null。
* @example
*
* var props = {
* user: {
* post: [{
* comments: 'test'
* }]
* }
* };
* getIn(['user', 'post', 0, 'comments'], props);
* // => test
*/
function getIn (p, o) {
return p.reduce(function (xs, x) {
return (xs && xs[x]) ? xs[x] : null
}, o)
}
/**
* Anagrams of string(带有重复项)
* 使用递归。对于给定字符串中的每个字母,为字母创建字谜。使用map()将字母与每部分字谜组合,然后使用reduce()将所有字谜组合到一个数组中,最基本情况是字符串长度等于2或1。
*
* @param str
* @returns {*}
* @example
*
* anagrams('abc');
* // => ['abc','acb','bac','bca','cab','cba']
*/
function anagrams (str) {
if (str.length < 2) { return str.length === 2 ? [str, str[1] + str[0]] : [str] }
return str.split('').reduce(function (acc, letter, i) {
return acc.concat(anagrams(str.slice(0, i) + str.slice(i + 1)).map(function (val) { return letter + val; }))
}, [])
}
/**
* 大写每个单词的首字母
*
* @param str
* @returns {string}
* @example
*
* capitalizeEveryWord('hello world!');
* // => 'Hello World!'
*/
function capitalizeEveryWord (str) {
return str.replace(/\b[a-z]/g, function (char) { return char.toUpperCase(); })
}
/**
* 获取数组的最后一项
*
* @param array
* @returns {boolean}
* @example
*
* last(['1,2,3']);
* // => '3';
*/
function last (array) {
return Array.isArray(array) && array.slice(-1)[0]
}
/**
* 测试函数所花费的时间
*
* @param callback
* @returns {*}
* @example
*
* timeTaken(() => Math.pow(2, 10));
* // => 1024
*/
function timeTaken (callback) {
if (typeof callback !== 'function') { throw new Error('callback 必须为可执行的函数') }
console.time('timeTaken');
var r = callback();
console.timeEnd('timeTaken');
return r
}
/**
* 滚动到顶部
* 使用document.documentElement.scrollTop或document.body.scrollTop获取到顶部的距离。从顶部滚动一小部分距离。
使用window.requestAnimationFrame()来滚动。
*
* @example
*
* scrollToTop();
*/
function scrollToTop () {
var c = document.documentElement.scrollTop || document.body.scrollTop;
if (c > 0) {
window.requestAnimationFrame(scrollToTop);
window.scrollTo(0, c - c / 8);
}
}
/**
* 是否为中文
*
* @param {string} str
* @returns {boolean}
* @example
*
* isChinese('中文');
* // => true
*/
function isChinese (str) {
var reg = /^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/;
return reg.test(str)
}
/**
* 是否为 HTML 标签
*
* @param {string} str
* @returns {boolean}
* @example
*
* isHTML('<p>123</p>');
* // => true
*/
function isHTML (str) {
var reg = /<("[^"]*"|'[^']*'|[^'">])*>/;
return reg.test(str)
}
/**
* 获取某月有多少天
* 摘自:https://segmentfault.com/a/1190000013041329
*
* @param {time} 时间
* @return {number} 天数
* @example
*
* getMonthOfDay('2018-1-29')
* // => 31
*/
function getMonthOfDay (time) {
var date = new Date(time);
var year = date.getFullYear();
var mouth = date.getMonth() + 1;
var days;
// 当月份为二月时,根据闰年还是非闰年判断天数
if (mouth === 2) {
days = (year % 4 === 0 && year % 100 === 0 && year % 400 === 0) || (year % 4 === 0 && year % 100 !== 0) ? 28 : 29;
} else if (mouth === 1 || mouth === 3 || mouth === 5 || mouth === 7 || mouth === 8 || mouth === 10 || mouth === 12) {
// 月份为:1,3,5,7,8,10,12 时,为大月.则天数为31;
days = 31;
} else {
// 其他月份,天数为:30.
days = 30;
}
return days
}
/**
* 返回指定长度的天数集合
* 摘自:https://segmentfault.com/a/1190000013041329
*
* @param {time} 时间
* @param {len} 长度
* @param {direction} 方向: 1: 前几天; 2: 后几天; 3:前后几天 默认 3
* @return {Array} 数组
* @example
*
* getDays('2018-1-29', 6, 1)
* // => ["2018-1-26", "2018-1-27", "2018-1-28", "2018-1-29", "2018-1-30", "2018-1-31", "2018-2-1"]
*/
function getDays (time, len, direction) {
var tt = new Date(time);
var getDay = function (day) {
var t = new Date(time);
t.setDate(t.getDate() + day);
var m = t.getMonth() + 1;
return t.getFullYear() + '-' + m + '-' + t.getDate()
};
var arr = [];
if (direction === 1) {
for (var i = 1; i <= len; i++) {
arr.unshift(getDay(-i));
}
} else if (direction === 2) {
for (var i$1 = 1; i$1 <= len; i$1++) {
arr.push(getDay(i$1));
}
} else {
for (var i$2 = 1; i$2 <= len; i$2++) {
arr.unshift(getDay(-i$2));
}
arr.push(tt.getFullYear() + '-' + (tt.getMonth() + 1) + '-' + tt.getDate());
for (var i$3 = 1; i$3 <= len; i$3++) {
arr.push(getDay(i$3));
}
}
return direction === 1 ? arr.concat([tt.getFullYear() + '-' + (tt.getMonth() + 1) + '-' + tt.getDate()])
: direction === 2 ? [tt.getFullYear() + '-' + (tt.getMonth() + 1) + '-' + tt.getDate()].concat(arr) : arr
}
/**
* 获取某个日期是当年中的第几天
*
* @param time
* @returns {number}
* @example
*
* getDayOfYear('2014-01-10')
* => 10
*/
function getDayOfYear (time) {
var firstDayYear = getFirstDayOfYear(time);
var numSecond = (new Date(time).getTime() - new Date(firstDayYear).getTime()) / 1000;
return Math.ceil(numSecond / (24 * 3600))
}
// 获取某年的第一天
function getFirstDayOfYear (time) {
var year = new Date(time).getFullYear();
return year + '-01-01 00:00:00'
}
/**
* 获取某个日期在这一年的第几周
*
* @param time
* @returns {number}
* @example
*
* getDayOfYearWeek('2014-01-10')
* => 2
*/
function getDayOfYearWeek (time) {
var numDays = getDayOfYear(time);
return Math.ceil(numDays / 7)
}
/**
* 获取某年有多少天
*
* @param time
* @returns {number}
* @example
*
* getYearOfDay('2014')
* => 365
*/
function getYearOfDay (time) {
var firstDayYear = getFirstDayOfYear$1(time);
var lastDayYear = getLastDayOfYear(time);
var numSecond = (new Date(lastDayYear).getTime() - new Date(firstDayYear).getTime()) / 1000;
return Math.ceil(numSecond / (24 * 3600))
}
// 获取某年的第一天
function getFirstDayOfYear$1 (time) {
var year = new Date(time).getFullYear();
return year + '-01-01 00:00:00'
}
// 获取某年最后一天
function getLastDayOfYear (time) {
var year = new Date(time).getFullYear();
var dateString = year + '-12-01 00:00:00';
var endDay = getMonthOfDay(dateString);
return year + '-12-' + endDay + ' 23:59:59'
}
/**
* 数字金额大写转换,最多支持千亿
*
* @param n {number} 数字金额
* @returns {string}
* @example
*
* changeMoneyToChinese(100111);
* => "壹拾万零壹佰壹拾壹元整"
*
* changeMoneyToChinese(7.52);
* => "柒元伍角贰分"
*
* changeMoneyToChinese(951434677682.00);
* => "玖仟伍佰壹拾肆亿叁仟肆佰陆拾柒万柒仟陆佰捌拾贰元整"
*/
function changeMoneyToChinese (n) {
n = +n;
if (isNaN(n)) {
console.warn('params type error');
return
}
if ((n > 0 && n.toString().length > 12) || (n < 0 && n.toString().length > 13)) {
throw new Error('number is too large')
}
var fraction = ['角', '分'];
var digit = [
'零', '壹', '贰', '叁', '肆',
'伍', '陆', '柒', '捌', '玖'
];
var unit = [
['元', '万', '亿'],
['', '拾', '佰', '仟']
];
var head = +n < 0 ? '欠' : '';
n = Math.abs(+n);
var s = '';
for (var i = 0; i < fraction.length; i++) {
s += (digit[Math.floor(shiftRight(n, 1 + i)) % 10] + fraction[i]).replace(/零./, '');
}
s = s || '整';
n = Math.floor(n);
for (var i$1 = 0; i$1 < unit[0].length && n > 0; i$1++) {
var p = '';
for (var j = 0; j < unit[1].length && n > 0; j++) {
p = digit[n % 10] + unit[1][j] + p;
n = Math.floor(shiftLeft(n, 1));
}
s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i$1] + s;
}
return head + s.replace(/(零.)*零元/, '元')
.replace(/(零.)+/g, '零')
.replace(/^整$/, '零元整')
}
// 向右移位
function shiftRight (number, digit) {
digit = parseInt(digit, 10);
var value = number.toString().split('e');
return +(value[0] + 'e' + (value[1] ? (+value[1] + digit) : digit))
}
function shiftLeft (number, digit) {
digit = parseInt(digit, 10);
var value = number.toString().split('e');
return +(value[0] + 'e' + (value[1] ? (+value[1] - digit) : -digit))
}
/**
* 数字转换成中文的大写数字
*
* @param num
* @returns {string}
* @example
*
* numberToChinese(10001010);
* => "一千万一千一十"
*/
function numberToChinese (num) {
var AA = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
var BB = ['', '十', '百', '千', '万', '亿', '点', ''];
var a = ('' + num).replace(/(^0*)/g, '').split('.');
var k = 0;
var re = '';
for (var i = a[0].length - 1; i >= 0; i--) {
switch (k) {
case 0:
re = BB[7] + re;
break
case 4:
if (!new RegExp('0{4}//d{' + (a[0].length - i - 1) + '}$')
.test(a[0])) { re = BB[4] + re; }
break
case 8:
re = BB[5] + re;
BB[7] = BB[5];
k = 0;
break
}
if (k % 4 === 2 && +a[0].charAt(i + 2) !== 0 && +a[0].charAt(i + 1) === 0) { re = AA[0] + re; }
if (+a[0].charAt(i) !== 0) { re = AA[a[0].charAt(i)] + BB[k % 4] + re; }
k++;
}
if (a.length > 1) {
// 加上小数部分(如果有小数部分)
re += BB[6];
for (var i$1 = 0; i$1 < a[1].length; i$1++) { re += AA[a[1].charAt(i$1)]; }
}
if (re === '一十') { re = '十'; }
if (re.match(/^一/) && re.length === 3) { re = re.replace('一', ''); }
return re
}
/**
* 科学计数法转化为数值字符串形式
*
* @param {number} num
* @returns {string}
* @example
*
* toNonExponential(3.3e-7);
* => // "0.00000033"
*
* toNonExponential(3e-7);
* => // "0.0000003"
*
* toNonExponential(1.401e10);
* => // "14010000000"
*
* toNonExponential(0.0004);
* => // "0.0004"
*/
function toNonExponential (num) {
if (typeof num !== 'number') { throw new TypeError('数据类型必须是 number') }
var m = num.toExponential().match(/\d(?:\.(\d*))?e([+-]\d+)/);
return num.toFixed(Math.max(0, (m[1] || '').length - m[2]))
}
/**
* 获取网址参数
* @param {string} url
* @returns {{}} 返回包含当前URL参数的对象。
* @example
*
* getURLParameters('http://url.com/page?name=Adam&surname=Smith');
* => // {name: 'Adam', surname: 'Smith'}
*/
function getURLParameters (url) {
if ( url === void 0 ) url = window.location.href;
if (typeof url !== 'string') { throw new TypeError('数据类型必须是 string') }
var paramsArr = url.match(/([^?=&]+)(=([^&]*))/g);
if (!paramsArr) { return {} }
return paramsArr.reduce(function (a, v) { return ((a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a); }, {}) // eslint-disable-line
}
/**
* 根据提供函数返回的值映射一个新对象
*
* @param obj
* @param fn
* @returns {{}}
* @example
*
* const users = {
fred: { user: 'fred', age: 40 },
pebbles: { user: 'pebbles', age: 1 }
};
* mapValues(users, u => u.age);
* // => { fred: 40, pebbles: 1 }
*/
var mapValues = function (obj, fn) { return Object.keys(obj).reduce(function (acc, k) {
acc[k] = fn(obj[k], k, obj);
return acc
}, {}); };
/**
* 根据提供函数生成的键生成一个新对象
* 使用 Object.keys(obj) 来迭代对象的键。 使用 Array.reduce() 创建一个具有相同值的新对象,并使用 fn 来映射键。
*
* @param obj
* @param fn
* @returns {{}}
* @example
*
* mapKeys({ a: 1, b: 2 }, (val, key) => key + val);
* // => { a1: 1, b2: 2 }
*/
var mapKeys = function (obj, fn) { return Object.keys(obj).reduce(function (acc, k) {
acc[fn(obj[k], k, obj)] = obj[k];
return acc
}, {}); };
/**
* 清除空格
*
* @param str
* @param type 1-所有空格 2-前后空格 3-前空格 4-后空格
* @returns {*}
* @example
*
* trim(' 123 ');
* // => 123
*/
function trim$1 (str, type) {
if ( type === void 0 ) type = 1;
if (typeof str !== 'string') { throw new Error('输入值必须为字符串') }
switch (type) {
case 1:
return str.replace(/\s+/g, '')
case 2:
return str.replace(/(^\s*)|(\s*$)/g, '')
case 3:
return str.replace(/(^\s*)/g, '')
case 4:
return str.replace(/(\s*$)/g, '')
default:
return str
}
}
/**
* 深层克隆对象
*
* @param obj
* @returns {*}
* @example
*
* const a = { foo: 'bar', obj: { a: 1, b: 2 } };
* const b = deepClone(a);
* // => a !== b, a.obj !== b.obj
*/
function deepClone (obj) {
var clone = Object.assign({}, obj);
Object.keys(clone).forEach(
function (key) { return (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]); }
);
return Array.isArray(obj) && obj.length
? (clone.length = obj.length) && Array.from(clone)
: Array.isArray(obj)
? Array.from(obj)
: clone
}
/**
* 深层映射对象键
*
* @param obj
* @param fn
* @returns {{}}
* @example
*
* const obj = {
foo: '1',
nested: {
child: {
withArray: [
{
grandChild: ['hello']
}
]
}
}
};
const upperKeysObj = deepMapKeys(obj, key => key.toUpperCase());
// =>
{
"FOO":"1",
"NESTED":{
"CHILD":{
"WITHARRAY":[
{
"GRANDCHILD":[ 'hello' ]
}
]
}
}
}
*/
function deepMapKeys (obj, fn) {
return Array.isArray(obj)
? obj.map(function (val) { return deepMapKeys(val, fn); })
: typeof obj === 'object'
? Object.keys(obj).reduce(function (acc, current) {
var val = obj[current];
acc[fn(current)] =
val !== null && typeof val === 'object' ? deepMapKeys(val, fn) : (acc[fn(current)] = val);
return acc
}, {})
: obj
}
/**
* 基于给定的键返回嵌套JSON对象中的目标值
*
* {@link https://30secondsofcode.org/object#dig}
* @param obj
* @param target
* @returns {any}
* @example
*
* const data = {
* level1: {
* level2: {
* level3: 'some data'
* }
* }
* };
* dig(data, 'level3');
* // => 'some data'
* dig(data, 'level4');
* // => undefined
*/
function dig (obj, target) {
return target in obj
? obj[target]
: Object.values(obj).reduce(function (acc, val) {
if (acc !== undefined) { return acc }
if (typeof val === 'object') { return dig(val, target) }
}, undefined)
}
/**
* 是否为空
* 如果a值是空对象,集合,没有可枚举属性或任何不被视为集合的类型,则返回true。
*
* {@link https://30secondsofcode.org/type#isempty}
* @param val
* @returns {boolean}
* @example
*
* isEmpty([]);
* // => true
* isEmpty({});
* // => true
* isEmpty('');
* // => true
* isEmpty([1, 2]);
* // => false
* isEmpty({ a: 1, b: 2 });
* // => false
* isEmpty('text');
* // => false
* isEmpty(123);
* // => true - type is not considered a collection
* isEmpty(true);
* // => true - type is not considered a collection
*/
function isEmpty (val) {
return val == null || !(Object.keys(val) || val).length
}
/**
* 从两个或多个对象的组合中创建一个新对象
*
* {@link https://30secondsofcode.org/object#merge}
* @param objs
* @returns {*}
* @example
*
* merge(
{
a: [{ x: 2 }, { y: 4 }],
b: 1
},
{
a: { z: 3 },
b: [2, 3],
c: 'foo'
});
* // => { a: [ { x: 2 }, { y: 4 }, { z: 3 } ], b: [ 1, 2, 3 ], c: 'foo' }
*/
function merge () {
var objs = [], len = arguments.length;
while ( len-- ) objs[ len ] = arguments[ len ];
return [].concat( objs ).reduce(
function (acc, obj) { return Object.keys(obj).reduce(function (a, k) {
acc[k] = Object.hasOwnProperty.call(acc, k) ? [].concat(acc[k]).concat(obj[k]) : obj[k];
return acc
}, {}); },
{}
)
}
/**
* url字符串拼接
*
* @param {string} baseURL
* @param {string} relativeURLs
* @returns {string} The combined URL
*/
function combineURLs (baseURL) {
var relativeURLs = [], len = arguments.length - 1;
while ( len-- > 0 ) relativeURLs[ len ] = arguments[ len + 1 ];
var length = relativeURLs.length;
if (length > 0) {
var relativeUrlsArr = relativeURLs.map(function (item) { return item.replace(/^\/+/, '').replace(/\/+$/, ''); });
var relativeUrlStr = relativeUrlsArr.join('/');
if (relativeURLs[length - 1].slice(-1) === '/') {
relativeUrlStr += '/';
}
return baseURL.replace(/\/+$/, '') + '/' + relativeUrlStr
} else {
return baseURL
}
}
/**
* 是否是微博内核
*
* @returns {boolean}
* @example
*
* inWeibo();
* // => false
*/
function inWeibo () {
if (typeof navigator === 'undefined') { return }
var ua = navigator.userAgent.toLowerCase();
return ua.indexOf('weibo') !== -1
}
/**
* 是否为有效的手机号,中国手机号(最宽松), 只要是1开头即可, 如果你的手机号是用来接收短信, 优先建议选择这一条
*
* @param {string} val
* @returns {boolean}
* @example
*
* isMobileLoose('008618311006933');
* // => true
*
* isMobileLoose('+8617888829981');
* // => true
*
* isMobileLoose('19119255642');
* // => true
*/
function isMobileLoose (val) {
var reg = /^(?:(?:\+|00)86)?1\d{10}$/;
return reg.test(val)
}
/**
* 是否为有效的银行卡号(10到30位, 覆盖对公/私账户, 参考[微信支付](https://pay.weixin.qq.com/wiki/doc/api/xiaowei.php?chapter=22_1))
*
* @param {string} val
* @returns {boolean}
* @example
*
* isValidBankNo('6234567890');
* // => true
*
* isValidBankNo('6222026006705354217');
* // => true
*/
function isValidBankNo (val) {
var reg = /^[1-9]\d{9,29}$/;
return reg.test(val)
}
/**
* 是否为有效的 base64格式
*
* @param {string} val
* @returns {boolean}
* @example
*
* isValidBase64Format('data:image/gif;base64,xxxx==')
* => true
*/
function isValidBase64Format (val) {
var reg = /^\s*data:(?:[a-z]+\/[a-z0-9-+.]+(?:;[a-z-]+=[a-z0-9-]+)?)?(?:;base64)?,([a-z0-9!$&',()*+;=\-._~:@/?%\s]*?)\s*$/i;
return reg.test(val)
}
/**
* 是否为有效的用户名,4到16位(字母,数字,下划线,减号)
*
* @param {string} val
* @param {number} minLength
* @param {number} maxLength
* @returns {boolean}
* @example
*
* isValidUserName('xiaohua_qq');
* // => true
*/
function isValidUserName (val, minLength, maxLength) {
if ( minLength === void 0 ) minLength = 4;
if ( maxLength === void 0 ) maxLength = 16;
var reg = new RegExp(("^[a-zA-Z0-9_-]{" + minLength + "," + maxLength + "}$"));
return reg.test(val)
}
/**
* 判断 iPhone X Series 机型,刘海屏
*
* @returns {boolean}
* @example
*
* isPhoneX()
* => true
*/
function isPhoneX () {
// X XS, XS Max, XR
var xSeriesConfig = [
{
devicePixelRatio: 3,
width: 375,
height: 812
},
{
devicePixelRatio: 3,
width: 414,
height: 896
},
{
devicePixelRatio: 2,
width: 414,
height: 896
}
];
// h5
if (typeof window !== 'undefined' && window) {
var isIOS = /iphone/gi.test(window.navigator.userAgent);
if (!isIOS) { return false }
var devicePixelRatio = window.devicePixelRatio;
var screen = window.screen;
var width = screen.width;
var height = screen.height;
return xSeriesConfig.some(function (item) { return item.devicePixelRatio === devicePixelRatio && item.width === width && item.height === height; })
}
return false
}
/**
* 是否是QQ浏览器内核
*
* @returns {boolean}
* @example
*
* inQQBrowser();
* // => false
*/
function inQQBrowser () {
if (typeof window.navigator === 'undefined') { return }
var ua = window.navigator.userAgent.toLowerCase();
return ua.indexOf('mqqbrowser') !== -1
}
/**
* 是否是UC浏览器内核
*
* @returns {boolean}
* @example
*
* inUCBrowser();
* // => false
*/
function inUCBrowser () {
if (typeof window.navigator === 'undefined') { return }
var ua = window.navigator.userAgent.toLowerCase();
return ua.indexOf('ucbrowser') !== -1
}
/**
* 两个值之间的深入比较,以确定它们是否相等
*
* @param {Object} a
* @param {Object} b
* @returns {*}
* @example
*
* equals({ a: [2, { e: 3 }], b: [4], c: 'foo' }, { a: [2, { e: 3 }], b: [4], c: 'foo' });
*
* // => true
*/
function equals (a, b) {
if (a === b) { return true }
if (a instanceof Date && b instanceof Date) { return a.getTime() === b.getTime() }
if (!a || !b || (typeof a !== 'object' && typeof b !== 'object')) { return a === b }
if (a === null || a === undefined || b === null || b === undefined) { return false }
if (a.prototype !== b.prototype) { return false }
var keys = Object.keys(a);
if (keys.length !== Object.keys(b).length) { return false }
return keys.every(function (k) { return equals(a[k], b[k]); })
}
/**
* 获取图片的base64 url
* @param {string} url 图片url
* @returns {Promise} 图片base64信息
*/
function getImgBase64 (url) {
var Img = new Image();
var dataURL = '';
Img.setAttribute('crossOrigin', 'anonymous');
Img.src = url;
return new Promise(function (resolve, reject) {
Img.onload = function () {
var canvas = document.createElement('canvas');
var width = Img.width;
var height = Img.height;
var ctx = canvas.getContext('2d');
var scale = 5;
ctx.scale(scale, scale);
canvas.width = width * scale;
canvas.height = height * scale;
ctx.drawImage(Img, 0, 0, width * scale, height * scale);
dataURL = canvas.toDataURL('image/png');
resolve(dataURL);
};
})
}
/**
* 过滤对象中为空的属性
*
* @param obj
* @returns {*}
* @example
*
* filterEmptyPropObj({name: 'foo', sex: ''})
* // => {name: 'foo'}
*/
function filterEmptyPropObj (obj) {
if (!(typeof obj === 'object')) { return }
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key) &&
(obj[key] === null || obj[key] === undefined || obj[key] === '')) {
delete obj[key];
}
}
return obj
}
exports.accAdd = accAdd;
exports.accDiv = accDiv;
exports.accMul = accMul;
exports.accSub = accSub;
exports.addChineseUnit = addChineseUnit;
exports.addClass = addClass;
exports.anagrams = anagrams;
exports.bytesToSize = bytesToSize;
exports.capitalizeEveryWord = capitalizeEveryWord;
exports.changeMoneyToChinese = changeMoneyToChinese;
exports.combineURLs = combineURLs;
exports.compareVersion = compareVersion;
exports.dataURLToBlob = dataURLToBlob;
exports.deepClone = deepClone;
exports.deepMapKeys = deepMapKeys;
exports.dig = dig;
exports.encrypt = encrypt;
exports.equals = equals;
exports.filterEmptyPropObj = filterEmptyPropObj;
exports.formatBankCard = formatBankCard;
exports.formatDate = formatDate;
exports.formatDateToTimeStamp = formatDateToTimeStamp;
exports.formatMoney = formatMoney;
exports.formatNumber = formatNumber;
exports.formatPhone = formatPhone;
exports.formatTimeAgo = formatTimeAgo;
exports.getBrowser = getBrowser;
exports.getDayOfYear = getDayOfYear;
exports.getDayOfYearWeek = getDayOfYearWeek;
exports.getDays = getDays;
exports.getDevice = getDevice;
exports.getDiffDay = getDiffDay;
exports.getImgBase64 = getImgBase64;
exports.getIn = getIn;
exports.getLocationHrefParam = getLocationHrefParam;
exports.getLocationSearchParam = getLocationSearchParam;
exports.getMonthOfDay = getMonthOfDay;
exports.getPixelRatio = getPixelRatio;
exports.getURLParameters = getURLParameters;
exports.getYearOfDay = getYearOfDay;
exports.hasClass = hasClass;
exports.htmlDecode = htmlDecode;
exports.htmlEncode = htmlEncode;
exports.inAlipay = inAlipay;
exports.inQQBrowser = inQQBrowser;
exports.inUCBrowser = inUCBrowser;
exports.inWeibo = inWeibo;
exports.inWeixin = inWeixin;
exports.isCardId = isCardId;
exports.isChinese = isChinese;
exports.isDigit = isDigit;
exports.isEmpty = isEmpty;
exports.isEmptyObject = isEmptyObject;
exports.isHTML = isHTML;
exports.isLeapYear = isLeapYear;
exports.isLetters = isLetters;
exports.isMobileLoose = isMobileLoose;
exports.isPhoneX = isPhoneX;
exports.isValidBankNo = isValidBankNo;
exports.isValidBase64Format = isValidBase64Format;
exports.isValidEmail = isValidEmail;
exports.isValidUserName = isValidUserName;
exports.last = last;
exports.mapKeys = mapKeys;
exports.mapValues = mapValues;
exports.merge = merge;
exports.numberToChinese = numberToChinese;
exports.preZeroFill = preZeroFill;
exports.removeClass = removeClass;
exports.scrollToTop = scrollToTop;
exports.timeTaken = timeTaken;
exports.toNonExponential = toNonExponential;
exports.trim = trim$1;