JavaScript 实用工具方法库
utils.js
// utils.js
/************************* 日期时间Begin *************************/
/**
* 日期时间格式化 方法一
* @param {*} fmt
* @param {*} date
* @returns
*/
export function dateFormat(fmt, date) {
let ret;
const opt = {
"Y+": date.getFullYear().toString(), // 年
"M+": (date.getMonth() + 1).toString(), // 月
"D+": date.getDate().toString(), // 日
"h+": date.getHours().toString(), // 时
"m+": date.getMinutes().toString(), // 分
"s+": date.getSeconds().toString() // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
};
};
return fmt;
}
/**
* 将一位数的数字格式化为两位:1->'01'
* 方法一
* @param {*} n
* @returns
*/
export function formatNumber(n) {
n = n.toString();
return n[1] ? n : '0' + n;
};
/**
* 将一位数的数字格式化为两位:1->'01'
* 方法二
* @param {*} val
* @returns
*/
export function fixedZero(val) {
return val * 1 < 10 ? `0${val}` : val;
}
/**
* 日期时间格式化 方法二
* 将时间日期格式化为:2023/01/11 09:38:00
* @param {*} date
* @returns
*/
export function formatTime(date) {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours();
const minute = date.getMinutes();
const second = date.getSeconds();
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(
':');
};
/** 根据出生日期计算年龄(yyyy-MM-dd) */
export function getBrithAge(birthday) {
const nowDay = new Date();
// 出生年月日
const birthYear = birthday.getFullYear();
const birthMonth = birthday.getMonth() + 1;
const birthDate = birthday.getDate();
// 当前年月日
const nowYear = nowDay.getFullYear();
const nowMonth = nowDay.getMonth() + 1;
const nowDate = nowDay.getDate();
// 计算年差
let age = nowYear - birthYear;
// 当前月小于出生月,则岁数不足
if (nowMonth < birthMonth) {
age -= 1;
} else if (nowMonth === birthMonth) {
// 当前日期小于出日期,则岁数不足
if (nowDate < birthDate) {
age -= 1;
}
}
return age;
}
// 获取上周时间段
export function getLastWeek(value) {
if (value == '' || value == undefined) {
return value;
}
if (value.length == 10) {
value = value * 1000;
}
const myDate = new Date(value - 7 * 24 * 3600 * 1000);
// 回退7天后是星期几?
const day = myDate.getDay();
const time = myDate.getDate() - day + (day === 0 ? -6 : 1);
const startTime = new Date(myDate.setDate(time));
const startDateTime =
startTime.getFullYear() +
'-' +
(startTime.getMonth() + 1) +
'-' +
startTime.getDate();
const endTime = new Date(myDate.setDate(time + 6));
const endDateTime =
endTime.getFullYear() +
'-' +
(endTime.getMonth() + 1) +
'-' +
endTime.getDate();
return {
startDateTime: startDateTime.replace(/\-/g, "/"),
endDateTime: endDateTime.replace(/\-/g, "/")
};
}
// 获取本周时间段
export function getCurrentWeek(value) {
if (value == '' || value == undefined) {
return value;
}
if (value.length == 10) {
value = value * 1000;
}
const myDate = new Date(value);
const nowTime = myDate.getTime();
const day = myDate.getDay();
const oneDayTime = 24 * 60 * 60 * 1000;
// 本周一时间戳
const MondayTime = nowTime - (day - 1) * oneDayTime;
// 本周日时间戳
const SundayTime = nowTime + (7 - day) * oneDayTime;
// 格式化时间
const monday = new Date(MondayTime);
const sunday = new Date(SundayTime);
const startTime = monday;
const startDateTime =
startTime.getFullYear() +
'-' +
(startTime.getMonth() + 1) +
'-' +
startTime.getDate();
const endTime = sunday;
const endDateTime =
endTime.getFullYear() +
'-' +
(endTime.getMonth() + 1) +
'-' +
endTime.getDate();
return {
startDateTime: startDateTime.replace(/\-/g, "/"),
endDateTime: endDateTime.replace(/\-/g, "/")
};
}
// 获取上个月时间段
export function getLastMonth(value) {
if (value == '' || value == undefined) {
return value;
}
if (value.length == 10) {
value = value * 1000;
}
// 获取上个月时间
const nowdays = new Date(value);
let year = nowdays.getFullYear();
let month = nowdays.getMonth();
if (month === 0) {
month = 12;
year = year - 1;
}
if (month < 10) {
month = '0' + month;
}
const yDate = new Date(year, month, 0);
// 上个月第一天
const startDateTime = year + '-' + month + '-01 00:00:00';
//上个月最后一天
const endDateTime = year + '-' + month + '-' + yDate.getDate() + ' 23:59:59';
return {
startDateTime: startDateTime.replace(/\-/g, "/"),
endDateTime: endDateTime.replace(/\-/g, "/")
};
}
// 获取本月时间段
export function getCurrentMonth(value) {
if (value == '' || value == undefined) {
return value;
}
if (value.length == 10) {
value = value * 1000;
}
const nowdays = new Date(value);
const year = nowdays.getFullYear();
let month = nowdays.getMonth() + 1;
if (month < 10) {
month = '0' + month;
}
const yDate = new Date(year, month, 0);
// 本月第一天
const startDateTime = year + '-' + month + '-01 00:00:00';
// 本月最后一天
const endDateTime = year + '-' + month + '-' + yDate.getDate() + ' 23:59:59';
return {
startDateTime: startDateTime.replace(/\-/g, "/"),
endDateTime: endDateTime.replace(/\-/g, "/")
};
}
/**
* 获取当前时间常用不同日期时间形式
* @returns
*/
export function commonTime() {
const time = new Date();
let obj = {
year: time.getYear(), //获取当前年份
fullYear: time.getFullYear(), //获取完整的年份(4位,1970-???)
month: time.getMonth(), //获取当前月份(0-11,0代表1月)
nowDate: time.getDate(), //获取当前日(1-31)
week: time.getDay(), //获取当前星期X(0-6,0代表星期天)
nowTime: time.getTime(), //获取当前时间(从1970.1.1开始的毫秒数)
hour: time.getHours(), //获取当前小时数(0-23)
min: time.getMinutes(), //获取当前分钟数(0-59)
sec: time.getSeconds(), //获取当前秒数(0-59)
mSec: time.getMilliseconds(), //获取当前毫秒数(0-999)
dateFormat: time.toLocaleDateString(), //获取当前日期
timeFormat: time.toLocaleTimeString(), //获取当前时间
dateTime: time.toLocaleString() //获取日期与时间
};
return obj;
}
/************************* 日期时间End *************************/
/************************* 输入校验Begin *************************/
// 正数验证
export function checkPositive(posInt) {
return RegExp(/^(([^0][0-9]+|0)\.([0-9]{1,10})$)|^(([^0][0-9]+|0)$)|^(([1-9]+)\.([0-9]{1,10})$)|^(([1-9]+)$)/)
.test(posInt);
}
// 正整数验证
export function checkPositiveInteger(posInt) {
return RegExp(/^[1-9]\d*$/).test(posInt);
}
// 手机号验证
export function checkMobile(mobile) {
return RegExp(/^1[3456789]\d{9}$/).test(mobile);
}
// 身份证号验证
export function checkIdCard(IdNumber) {
// 身份证号码为15位或18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X
return RegExp(/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/).test(IdNumber);
}
// 验证输入是否有Emoji表情和特殊字符
export function checkEmojiAndSpecial(input) {
const emojiRegStr =
/[^\u0020-\u007E\u00A0-\u00BE\u2E80-\uA4CF\uF900-\uFAFF\uFE30-\uFE4F\uFF00-\uFFEF\u0080-\u009F\u2000-\u201f\u2026\u2022\u20ac\r\n]/g;
const specialRegStr = "[`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()——|{}【】‘;:”“'。,、?]";
return RegExp(emojiRegStr).test(input) || RegExp(specialRegStr).test(input);
}
/************************* 输入校验End *************************/
export function getPlainNode(nodeList, parentPath = '') {
const arr = [];
nodeList.forEach(node => {
const item = node;
item.path = `${parentPath}/${item.path || ''}`.replace(/\/+/g, '/');
item.exact = true;
if (item.children && !item.component) {
arr.push(...getPlainNode(item.children, item.path));
} else {
if (item.children && item.component) {
item.exact = false;
}
arr.push(item);
}
});
return arr;
}
export function digitUppercase(n) {
const fraction = ['角', '分'];
const digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
const unit = [['元', '万', '亿'], ['', '拾', '佰', '仟']];
let num = Math.abs(n);
let s = '';
fraction.forEach((item, index) => {
s += (digit[Math.floor(num * 10 * 10 ** index) % 10] + item).replace(/零./, '');
});
s = s || '整';
num = Math.floor(num);
for (let i = 0; i < unit[0].length && num > 0; i += 1) {
let p = '';
for (let j = 0; j < unit[1].length && num > 0; j += 1) {
p = digit[num % 10] + unit[1][j] + p;
num = Math.floor(num / 10);
}
s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
}
return s
.replace(/(零.)*零元/, '元')
.replace(/(零.)+/g, '零')
.replace(/^整$/, '零元整');
}
function getRelation(str1, str2) {
if (str1 === str2) {
console.warn('Two path are equal!'); // eslint-disable-line
}
const arr1 = str1.split('/');
const arr2 = str2.split('/');
if (arr2.every((item, index) => item === arr1[index])) {
return 1;
} else if (arr1.every((item, index) => item === arr2[index])) {
return 2;
}
return 3;
}
function getRenderArr(routes) {
let renderArr = [];
renderArr.push(routes[0]);
for (let i = 1; i < routes.length; i += 1) {
let isAdd = false;
// 是否包含
isAdd = renderArr.every(item => getRelation(item, routes[i]) === 3);
// 去重
renderArr = renderArr.filter(item => getRelation(item, routes[i]) !== 1);
if (isAdd) {
renderArr.push(routes[i]);
}
}
return renderArr;
}
/**
* Get router routing configuration
* { path:{name,...param}}=>Array<{name,path ...param}>
* @param {string} path
* @param {routerData} routerData
*/
export function getRoutes(path, routerData) {
let routes = Object.keys(routerData).filter(
routePath => routePath.indexOf(path) === 0 && routePath !== path
);
// Replace path to '' eg. path='user' /user/name => name
routes = routes.map(item => item.replace(path, ''));
// Get the route to be rendered to remove the deep rendering
const renderArr = getRenderArr(routes);
// Conversion and stitching parameters
const renderRoutes = renderArr.map(item => {
const exact = !routes.some(route => route !== item && getRelation(route, item) === 1);
return {
exact,
...routerData[`${path}${item}`],
key: `${path}${item}`,
path: `${path}${item}`,
};
});
return renderRoutes;
}
// 判断是否为合法 Url
export function isUrl(path) {
const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/g;
return reg.test(path);
}
/**
* 判断当前url是否合法 http(s)
* @param {string} URL
* 被检测 URL
* @returns {boolean}
* true - 合法有效URL,false - 不合法无效 URL
*/
export function checkURL(URL) {
var str = URL,
Expression = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/,
objExp = new RegExp(Expression);
if (objExp.test(str) == true) {
return true
} else {
return false
}
}
// 计算base64编码图片大小
export function getBase64ImageSize(base64) {
const indexBase64 = base64.indexOf('base64,');
if (indexBase64 < 0) return -1;
const str = base64.substr(indexBase64 + 6);
// 大小单位:字节
return (str.length * 0.75).toFixed(2);
}
/**
* 图像压缩,默认同比例压缩
* @param {Object} imgPath
* 图像base64编码字符串或图像可访问路径
* @param {Object} obj
* obj 对象 有 width, height, quality(0-1)
* @param {Object} maxSize
* 指定压缩后的文件大小,单位:字节
* @param {Object} callback
* 回调函数有一个参数,base64的字符串数据
*/
export function compressedImage(path, obj, maxSize, callback) {
let img = new Image();
img.src = imgPath;
img.onload = function () {
const that = this;
// 默认按比例压缩
let w = that.width,
h = that.height,
scale = w / h;
w = obj.width || w;
h = obj.height && obj.height * (w / scale) || h;
// 生成canvas
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
canvas.width = w;
canvas.height = h;
ctx.drawImage(that, 0, 0, w, h);
// 图像质量,默认图片质量为0.8
let quality = 0.8;
if (obj.quality && obj.quality > 0 && obj.quality <= 1) {
quality = obj.quality;
}
// quality值越小,所绘制出的图像越模糊
let newBase64Image = canvas.toDataURL('image/jpeg', quality);
let fileSize = getBase64ImageSize(newBase64Image);
if (fileSize > maxSize && quality > 0.01) {
if (quality > 0.05) {
quality = quality - 0.05;
} else {
quality = 0.01;
}
compressedImage(imgPath, {
quality: quality
}, maxSize, callback);
return;
}
// 回调函数返回压缩后的 base64图像
callback(newBase64Image);
}
}
/**
* 将扁平数组转换为树形对象,
* 适用于来自同一个表的数据,即idName的数据不重复
*
* @param {*} flatData 同级数组数据
* @param {*} idName 唯一id
* @param {*} pidName 父级id
* @param {*} nameName 自定义(Cascader 级联选择器)键名称
* @param {*} valueName 自定义(Cascader 级联选择器)值名称
* @returns 树形结构数组数据,适用于Cascader 级联选择器组件
*/
export function convertToTree(flatData, idName, pidName, nameName, valueName) {
let treeData = [];
if (!Array.isArray(flatData)) {
return treeData;
}
flatData.forEach((item) => {
delete item.children;
});
let map = {};
flatData.forEach((item) => {
// 深拷贝,该方式将使该转换方法失效
// map[item[idName]] = JSON.parse(JSON.stringify(item));
// 浅拷贝,将对 item 的引用传递给 map
map[item[idName]] = item;
});
flatData.forEach((item) => {
// 深拷贝,该方式将使该转换方法失效
// let parent = JSON.parse(JSON.stringify(map[item[pidName]]));
// 浅拷贝,将对 map 的引用传递给 parent
let parent = map[item[pidName]];
if (parent) {
// 利用了浅拷贝的引用传递,最终 flatData 中的 item 将会改变
(parent.children || (parent.children = [])).push(
nameName && valueName ? Object.assign(item, { label: item[nameName], id: item[valueName] }) : item);
} else {
treeData.push(
nameName && valueName ? Object.assign(item, { label: item[nameName], id: item[valueName] }) : item);
}
});
return treeData;
}
// 将树形结构数据转换为扁平数组
export function convertToFlat(treeData) {
let flatData = [];
for (let i = 0; i < treeData.length; i++) {
if (treeData[i].childrens) {
flatData.push(...convertToFlat(treeData[i].childrens));
delete treeData[i].childrens;
}
flatData.push({ ...treeData[i] });
}
return flatData;
}
// 将base64 转换为File
export function base64ToFile(base64, fileName) {
let arr = base64.split(',');
let mime = arr[0].match(/:(.*?);/)[1];
let bstr = atob(arr[1]);
let n = bstr.length;
let u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], fileName, { type: mime });
}
// 将base64 转换为Blob
export function base64ToBlob(base64) {
var arr = base64.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {
type: mime
});
}
// 将Blob转换为 File
export function blobToFile(blob, fileName) {
return new File([blob], fileName);
}
// 将JSON 对象序列化为query string
export function objectToQueryString(obj) {
return Object.entries(obj).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join('&');
}
// 将query string 反序列化为JSON 对象
export function queryStringToObject(queryString) {
let obj = {};
let arr = queryString.split("&");
for (let i = 0; i < arr.length; i++) {
let temp = arr[i].split("=");
obj[temp[0]] = temp[1];
}
return obj;
}
// 防抖
export function debounce(fn, delay) {
let timer = null;
return function () {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
timer = null;
}, delay);
};
}
// 节流
export function throttle(fn, delay) {
let timer = null;
return function () {
const context = this;
const args = arguments;
if (!timer) {
timer = setTimeout(function () {
fn.apply(context, args);
timer = null;
}, delay);
}
};
}
/**
* 名字脱敏 保留首位
* @param fullName
* @returns {string}
*/
export function desensitizedName(fullName) {
if (!fullName) {
return "";
}
let str = fullName.substr(0, 1);
for (let i = 0; i < fullName.length - 1; i++) {
str += '*';
}
return str;
}
/**
* 通过两点间的经纬度计算两点间的距离
* @param {*} lat1 起点纬度
* @param {*} lng1 起点经度
* @param {*} lat2 终点纬度
* @param {*} lng2 终点经度
* @returns
*/
export function getDistance(lat1, lng1, lat2, lng2) {
var radLat1 = lat1 * Math.PI / 180.0;
var radLat2 = lat2 * Math.PI / 180.0;
var a = radLat1 - radLat2;
var b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;
var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
s = s * 6378.137; // EARTH_RADIUS;
s = Math.round(s * 10000) / 10000;
return s;
}
/**
* 判断浏览器类型
* @returns
*/
export function getBrowserType() {
const ua = window.navigator.userAgent;
if (/MicroMessenger/.test(ua)) {
// 微信
return 'wechat';
} else if (/AlipayClient/.test(ua)) {
// 支付宝
return 'alipay';
} else if (/UnionPay/.test(ua)) {
// 云闪付
return 'up';
} else if (/BankabcAndroid|BankabciPhone/.test(ua)) {
// 农行掌银
return 'abc';
} else {
return 'other';
}
}
/**
* 获取浏览器名称
* @returns
*/
export function getBrowserName() {
const userAgent = navigator.userAgent;
if (userAgent.indexOf("Opera") > -1 || userAgent.indexOf("OPR") > -1) {
return 'Opera';
} else if (userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1) {
return 'IE';
} else if (userAgent.indexOf("Edge") > -1) {
return 'Edge';
} else if (userAgent.indexOf("Firefox") > -1) {
return 'Firefox';
} else if (userAgent.indexOf("Safari") > -1 && userAgent.indexOf("Chrome") == -1) {
return 'Safari';
} else if (userAgent.indexOf("Chrome") > -1 && userAgent.indexOf("Safari") > -1) {
return 'Chrome';
} else if (!!window.ActiveXObject || "ActiveXObject" in window) {
return 'IE>=11';
} else {
return 'Unkonwn';
}
}
/**
* 获取浏览器名称及其版本号
* @returns
*/
export function getBrowserNameVersion() {
console.log('navigator.userAgent', navigator.userAgent);
var Sys = {};
var ua = navigator.userAgent.toLowerCase();
var s;
(s = ua.match(/rv:([\d.]+)\) like gecko/)) ? Sys.ie = s[1] :
(s = ua.match(/msie ([\d\.]+)/)) ? Sys.ie = s[1] :
(s = ua.match(/edge\/([\d\.]+)/)) ? Sys.edge = s[1] :
(s = ua.match(/firefox\/([\d\.]+)/)) ? Sys.firefox = s[1] :
(s = ua.match(/(?:opera|opr).([\d\.]+)/)) ? Sys.opera = s[1] :
(s = ua.match(/chrome\/([\d\.]+)/)) ? Sys.chrome = s[1] :
(s = ua.match(/version\/([\d\.]+).*safari/)) ? Sys.safari = s[1] : 0;
// 根据关系进行判断
if (Sys.ie) return ('IE: ' + Sys.ie);
if (Sys.edge) return ('EDGE: ' + Sys.edge);
if (Sys.firefox) return ('Firefox: ' + Sys.firefox);
if (Sys.chrome) return ('Chrome: ' + Sys.chrome);
if (Sys.opera) return ('Opera: ' + Sys.opera);
if (Sys.safari) return ('Safari: ' + Sys.safari);
return 'Unkonwn';
}
/**
* 比较版本号
* @param {*} version1
* 版本号1
* @param {*} version2
* 版本号2
* @returns
* 如果version1 > version2,返回1;
* 如果version1 < version2,返回-1,
* 其他情况返回0
*/
export function compareVersion(version1, version2) {
const newVersion1 = `${version1}`.split('.').length < 3 ? `${version1}`.concat('.0') : `${version1}`;
const newVersion2 = `${version2}`.split('.').length < 3 ? `${version2}`.concat('.0') : `${version2}`;
// 计算版本号大小,转化大小
function toNum(a) {
const c = a.toString().split('.');
const num_place = ["", "0", "00", "000", "0000"],
r = num_place.reverse();
for (let i = 0; i < c.length; i++) {
const len = c[i].length;
c[i] = r[len] + c[i];
}
return c.join('');
}
// 检测版本号是否需要更新
function checkPlugin(a, b) {
const numA = toNum(a);
const numB = toNum(b);
return numA > numB ? 1 : numA < numB ? -1 : 0;
}
return checkPlugin(newVersion1, newVersion2);
}
/**
* 产生随机数组
* @param {*} num 生成数组长度
* @param {*} arr 原数组
* @returns 指定长度和原数组的随机数组
*/
export function randomArr(num, arr) {
var arrNew = [];
var copyArr = arr.join('&').split('&')
for (var i = 0; i < num; i++) {
var _num = Math.floor(Math.random() * copyArr.length)
var mm = copyArr[_num];
copyArr.splice(_num, 1)
arrNew.push(mm)
}
return arrNew
}
收集整理中...