前端常用函数整理(我可是把收藏的方法都放上来了,给个好评!)
/**
window.scroll(x, y), window.scrollTo(x, y) 功能一致, 设置滚动条滚动距离
window.scrollBy(x, y) 设置滚动条滚动距离, 在之前的值的基础上累加; 例子:可实现自动阅读功能
遍历时间上: for循环遍历 < for…of遍历 < forEach遍历 < for…in遍历 < map遍历
for循环遍历可以通过 break 关键字跳出循环
解决苹果手机输入框聚焦后,页面自动放大问题 -- 【重要】
input, input:focus,
textarea, textarea:focus,
select, select:focus{
font-size: 16px !important;
}
扩展:
cookie: 最好放在 HTTP 请求的头信息 Authorization 字段里面
postcss-pxtorem 是一款 postcss 插件,用于将单位转化为 rem
深拷贝的解决方案 :
使用lodash 插件
使用递归解决深拷贝
如果数据中没有函数,undefined 可以使用json.stringify+json.parse实现深拷贝
超出显示省略号:
white-space nowrap 让文字在一行内显示, 不换行
overflow hidden 当内容超过盒子宽度, 隐藏溢出部分
text-overflow ellipsis 如果溢出的内容是文字, 就用省略号代替
-webkit-line-clamp 数字 控制可以显示的行数
单行:
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
多行:
overflow: hidden; //超出的文本隐藏
text-overflow: ellipsis; //溢出用省略号显示
display: -webkit-box;
-webkit-line-clamp: 2; // 超出多少行
-webkit-box-orient: vertical;
滚动条样式:
::-webkit-scrollbar {
width: 12px;
height: 10px;
}
::-webkit-scrollbar-thumb {
height: 30px;
background-color: rgb(153 153 153);
-webkit-border-radius: 7px;
outline-offset: -2px;
border: 2px solid rgb(255 255 255);
}
::-webkit-scrollbar-track-piece {
background-color: rgb(255 255 255);
-webkit-border-radius: 3px;
}
原生深拷贝 structuredClone:
structuredClone()
微信小程序地理位置问题:
微信官方文档:https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#requiredPrivateInfos
详情:https://blog.csdn.net/qq_41602125/article/details/126710029
在 app.json 中,与 pages 同级:
精确位置信息:
"requiredPrivateInfos": [
"getFuzzyLocation",
"getLocation",
"onLocationChange",
"startLocationUpdateBackground"
"chooseAddress"
]
模糊位置信息:
"requiredPrivateInfos": [
"getFuzzyLocation"
]
注意:声明了模糊位置信息就无法声明精确位置信息。
若同时声明模糊位置信息和精确位置信息,在编译代码时会出现错误
navigator.onLineAPI 来检测网络状态(兼容性有点差)
匹配字符串:只能是数字或小数; d{1,3} 可以修改匹配个数
rex = /^((0{1}\.\d{1,3})|([1-9]\d*\.{1}\d{1,3})|([1-9]+\d*))$/;
*/
window.myPlugin = {
/**
* 关键字样式
* @param {Array} list 原数组
* @param {Object} params 参数对象
* class 样式类
* style 行内样式
* keywords 关键字
* callback 回调函数
* @returns {Array} 新数组
*/
keywordsStyleFun(list, params) {
if (!Array.isArray(list)) throw Error('keywordsReplace方法的参数1不是一个数组!');
if (typeof params !== 'object' || params === null) throw Error('keywordsReplace方法的参数2(对象)不是一个对象!');
if (!params.keywords) throw Error('keywordsReplace方法的参数2(对象)的属性keywords不能为空!');
params = Object.assign({
class: 'keywords_class',
style: 'color:#1890ff;',
keywords: '',
childListName: 'childList',
callback: () => { },
}, params);
let keywordsStyle = `<span class="${params.class}" style="${params.style}">${params.keywords}</span>`;
// let keywordsStyle = `<rich-text class="${params.class}" style="${params.style}" nodes="${params.keywords}"></rich-text>`; // 微信小程序
return list.map(item => {
let row = {
isKeywords: false,
...item
}
if (row.title.indexOf(params.keywords) > -1) {
row.isKeywords = true;
row.title = row.title.replace(params.keywords, keywordsStyle);
}
if (row[params.childListName] && row[params.childListName].length > 0) {
row[params.childListName] = row[params.childListName].map(childItem => {
let childRow = {
isKeywords: false,
...childItem
}
if (childRow.childTitle.indexOf(params.keywords) > -1) {
childRow.isKeywords = true;
childRow.childTitle = childRow.childTitle.replace(params.keywords,
keywordsStyle);
}
return childRow;
});
}
return row;
});
},
/**
* 找到最接近 n 的值
* @param {Array} arr 数组
* @param {Number|String} n
* @param {String} key 对象的键名
* @returns 数字或对象
*/
closest(arr, n, key) {
if (key) {
return arr[arr.map(item => Math.abs(item[key] - n)).findIndex((val, index, findArr) => Math.min(...findArr) == val)];
} else {
return arr[arr.map(item => Math.abs(item - n)).findIndex((val, index, findArr) => Math.min(...findArr) == val)];
}
},
/**
* 把base64转成File对象
* @param {String} base64Data base64数据
* @param {String} name File对象的名称
* @returns File对象
*/
base64ToFile(base64Data, name) {
const dataArr = base64Data.split(',')
const type = dataArr[0].match(/:(.*);/)[1]
const byteString = window.atob(dataArr[1])
const buffer = new ArrayBuffer(byteString.length)
const arr = new Uint8Array(buffer)
for (let i = 0; i < byteString.length; i++) {
arr[i] = byteString.charCodeAt(i)
}
return new File([buffer], name, { type })
},
/**
* 使用 jsqr 插件解析二维码: npm install jsqr
* 需要在 html 中创建:
* <canvas ref="myCanvas" id="myCanvas" width="600" height="600" style="display: none" />
* @param {} file 上传的二维码图片 e.target.files[0]
* @returns {}
*/
jsqrParseQRCode(file) {
// jsqr解析二维码
let img = new Image()
let reader = new FileReader();
reader.readAsDataURL(file)
// console.log(file)
reader.onload = (e) => {
console.log(e)
img.src = e.target.result
let myCanvas = document.getElementById('myCanvas');
// let myCanvas = _this.$refs.myCanvas;
let myCanvaswd = myCanvas.getContext('2d')
img.onload = function () {
myCanvaswd.drawImage(img, 0, 0, 600, 600)
let imageData = myCanvaswd.getImageData(0, 0, 600, 600)
let picData = {}
/*
imageData.data: Uint8ClampedArray表单中的一个RGBA像素值
imageData.width: 要解码的图像的宽度
imageData.height: 要解码的图像的高度
inversionAttempts:
attemptBoth(默认) 尝试两者
dontInvert 不要倒置
onlyInvert 仅反转
invertFirst 反转第一个
*/
picData = jsqr(imageData.data, imageData.width, imageData.height, {
inversionAttempts: 'attemptBoth'
})
console.log(picData)
if (picData && picData.data) {
} else {
// _this.$message.error('识别二维码失败,请重新上传');
}
}
}
},
/**
* 按字母排序(忽略大小写)
* @param {Array} arr 需要排序的数组
* @param {String} key 若,数组的元素为对象,key 为键名
* @param {Array} arr
* @returns {Array} 新数组
* 备注:
* 1.若需要对姓名的拼音首字母进行排序,可使用当前目录的 pinyin.js 的方法提取姓名的拼音
* 2.若对姓名的拼音首字母进行分组,先使用 sortAlphabetically 方法排序,再使用 grouping 方法分组
* 参考例子:
let arr = ['张三', '李四', '王五', '赵六', '黄蓉', '小明', '小红', '老六', '饕餮']
let newArr = arr.map(item => {
let row = {};
row.pinyin = pinyin.getFullChars(item);
row.initial = row.pinyin.split('')[0];
row.name = item;
return row;
});
let sortNewArr = myPlugin.sortAlphabetically(newArr, 'initial');
console.log(sortNewArr)
let list = myPlugin.grouping(sortNewArr, 'initial');
console.log(list)
*
*/
sortAlphabetically(arr, key) {
let list = arr.slice();
if (key) {
list.sort(function (s1, s2) {
x1 = s1[key].toUpperCase();
x2 = s2[key].toUpperCase();
if (x1 < x2) {
return -1;
}
if (x1 > x2) {
return 1;
}
return 0;
});
} else {
list.sort(function (s1, s2) {
x1 = s1.toUpperCase();
x2 = s2.toUpperCase();
if (x1 < x2) {
return -1;
}
if (x1 > x2) {
return 1;
}
return 0;
});
}
return list;
},
/**
* 两日期之间相差的天数
* @param {Date, Date} date1 日期1
* @param {Date, Date} date2 日期2
* @returns {Number}
*/
getDayDiff(date1, date2) {
date1 = typeof date1 == 'string' ? new Date(date1) : date1;
date2 = typeof date2 == 'string' ? new Date(date2) : date2;
// 86400000 = 1000 * 60 * 60 * 24 一天
return Math.ceil(Math.abs(date1.getTime() - date2.getTime()) / 86400000);
},
/**
* 将华氏温度转换为摄氏温度
* @param {Number|String} 度数
* @returns {Number}
*/
fahrenheitToCelsius(fahrenheit) {
return (fahrenheit - 32) * 5 / 9;
},
/**
* 将摄氏温度转华氏温度
* @param {Number|String} 度数
* @returns {Number}
*/
celsiusToFahrenheit(celsius) {
return celsius * 9 / 5 + 32;
},
/**
* 获取参数/获取浏览器url参数,并转化为对象
* @param {String} search 默认 获取浏览器url参数
* @returns {}
* 注意:若 URLSearchParams 无效 ,请 npm install url-search-params-polyfill
*/
getLocationSeearchParams(search) {
var str = search || window.location.search;
var url = new URL(str);
var searchParams = new URLSearchParams(str);
// 把键值对列表转换为一个对象
var paramsObj = Object.fromEntries(searchParams.entries());
url.paramsObj = paramsObj;
return url
},
/**
* 屏蔽部分字符串
* @param {String} str
* @returns {String}
*/
maskedPartString(str) {
return str.replace(/^(.{4})(?:\d+)(.{4})$/, "$1******$2");
},
/**
* 获取星期的中文和是否是工作日
* @param {Number} week 0-6
* @returns {String}
* '星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'
*/
getWeekCN(week) {
let weekArr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
// 是否是工作日
let isWeekday = week % 6 !== 0 ? true : false;
return {
isWeekday,
weekCN: weekArr[week],
}
},
/**
* 获取当前日期的前几天/后几天
* @param {String|Date} dateVal 日期:2022-09-01
* @param {Number} symbol 负数时,为前几天; 正数是,为后几天
* @returns {Object}
* 返回当前日期 前几天/后几天 的对象
* 包含 日期字符串、日期对象、年、月、日、时、分、秒、星期、时间戳
*/
getPrevNextDate(dateVal = new Date(), symbol) {
let date = new Date(dateVal);
date.setDate(date.getDate() + symbol);
let year = date.getFullYear();
let month = date.getFullYear();
let day = date.getFullYear();
let hour = date.getFullYear();
let minute = date.getFullYear();
let second = date.getFullYear();
month = month + 1 < 10 ? "0" + (month + 1) : month + 1;
day = day < 10 ? "0" + day : day;
hour = hour + 1 < 10 ? "0" + (hour + 1) : hour + 1;
minute = minute + 1 < 10 ? "0" + (minute + 1) : minute + 1;
second = second + 1 < 10 ? "0" + (second + 1) : second + 1;
let dateText = `${year}-${month}-${day} ${hour}:${minute}:${second}`;
let week = date.getDay(); // 0 为星期日
let timeStamp = date.getTime(); // 时间戳
return {
dateText,
date,
year,
month,
day,
hour,
minute,
second,
week,
timeStamp
}
},
/**
* 判断两个日期是否在范围之内
* @param {String} date1 时间:2022-09-01
* @param {String} date2 时间:2022-09-30
* @param {Number} differ 设置的两个日期范围,如:30, 2022-09-01 ~ 2022-09-30
* @returns {Boolean} true 范围在 differ 内; false 范围在 differ 外
*/
operatingFormatter(date1, date2, differ = 30) {
differ = Math.sign(differ) == 1 ? -differ : differ;
let GetDateStr = function (date, AddDayCount) {
var dd = new Date(date);
if (dd == 'Invalid Date') throw Error(dd)
dd.setDate(dd.getDate() + AddDayCount);//获取AddDayCount天后的日期
var y = dd.getFullYear();
var m = (dd.getMonth() + 1) < 10 ? "0" + (dd.getMonth() + 1) : (dd.getMonth() + 1);//获取当前月份的日期,不足10补0
var d = dd.getDate() < 10 ? "0" + dd.getDate() : dd.getDate();//获取当前几号,不足10补0
return y + "-" + m + "-" + d;
}
let checkDate = function (date1, date2) {
var oDate1 = new Date(date1);
var oDate2 = new Date(date2);
if (oDate1 == 'Invalid Date') throw Error(oDate1)
if (oDate2 == 'Invalid Date') throw Error(oDate2)
if (oDate1.getTime() > oDate2.getTime()) {
return true; // 范围在 differ 内
} else {
return false; // 范围在 differ 外
}
}
return checkDate(date1, GetDateStr(date2, differ));
},
/**
* JS转换时间戳为“刚刚”、“1分钟前”、“2小时前”“1天前”等格式
* @param {String} stringTime 时间:2022-09-07
* @returns {String}
*/
getTimer(stringTime) {
let minute = 1000 * 60; // 1分钟
let hour = minute * 60; // 1小时 1000*60*60
let day = hour * 24; // 1天 1000*60*60*24
let week = day * 7; // 1周 1000*60*60*24*7
let month = day * 30; // 1个月 1000*60*60*24*30
let time1 = new Date().getTime();//当前的时间戳
let time2 = Date.parse(new Date(stringTime));//指定时间的时间戳
let time = time1 - time2;
let result = null;
if (time < 0) {
console.log("设置的时间不能早于当前时间!");
} else if (time / month >= 1) {
result = "发布于" + parseInt(time / month) + "月前!";
} else if (time / week >= 1) {
result = "发布于" + parseInt(time / week) + "周前";
} else if (time / day >= 1) {
result = "发布于" + parseInt(time / day) + "天前";
} else if (time / hour >= 1) {
result = "发布于" + parseInt(time / hour) + "小时前";
} else if (time / minute >= 1) {
result = "发布于" + parseInt(time / minute) + "分钟前";
} else {
result = "刚刚";
}
return result;
},
/**
* 判断两个时间是否有交集
* @param {*} start1 开始时间1
* @param {*} end1 结束时间1
* @param {*} start2 开始时间2
* @param {*} end2 结束时间2
* @returns {Boolean} true || false
*/
isDateIntersection(start1, end1, start2, end2) {
var startdate1 = new Date(start1.replace("-", "/").replace("-", "/"));
var enddate1 = new Date(end1.replace("-", "/").replace("-", "/"));
var startdate2 = new Date(start2.replace("-", "/").replace("-", "/"));
var enddate2 = new Date(end2.replace("-", "/").replace("-", "/"));
if (startdate1 >= startdate2 && startdate1 <= enddate2) {
return true;
}
if (enddate1 >= startdate2 && enddate1 <= enddate2) {
return true;
}
if (startdate1 <= startdate2 && enddate1 >= enddate2) {
return true;
}
return false;
},
/**
* 计算小时差
* 若是要计算从开始时间到结束时间共几天的话需要加1
* startDate: 开始时间;格式: YYYY-MM-DD 或者 YYYY-MM-DD hh:mm:ss
* endDate: 结束时间;格式: YYYY-MM-DD 或者 YYYY-MM-DD hh:mm:ss
* */
differHourTime(startDate, endDate) { // 一小时等于60 * 60 * 1000毫秒
return Math.floor((new Date(endDate).getTime() - new Date(startDate).getTime()) / 3600000)
},
/**
* 计算分钟差
* 若是要计算从开始时间到结束时间共几天的话需要加1
* startDate: 开始时间;格式: YYYY-MM-DD 或者 YYYY-MM-DD hh:mm:ss
* endDate: 结束时间;格式: YYYY-MM-DD 或者 YYYY-MM-DD hh:mm:ss
* */
differMinuteTime(startDate, endDate) { // 一分钟等于60 * 1000毫秒
return Math.floor((new Date(endDate).getTime() - new Date(startDate).getTime()) / 60000)
},
/**
* 判断是否是空值
*/
keyIsNull(val) {
if (val === '' || val === null || val === undefined) return true;
return false;
},
/**
* 获取当前日期30天以前的日期
* @returns {String} 返回字符串日期,如:2022-10-01
*/
getDateAfter30() {
let date = new Date();
// 获取三十天前日期
// 最后一个数字30可改,30天的意思
var lw = new Date(date - 1000 * 60 * 60 * 24 * 30);
var lastY = lw.getFullYear();
var lastM = lw.getMonth() + 1;
var lastD = lw.getDate();
// 三十天之前日期
var startdate = lastY + "-" + (lastM < 10 ? "0" + lastM : lastM) + "-" + (lastD < 10 ? "0" + lastD : lastD);
return startdate;
},
/**
* 保留小数(没有四舍五入)
* @param {Number} val 数值
* @param {Number} amount 保留多少位(默认保留2位)
* @returns {Number|String} 返回数值|字符串
*/
keepDecimals(val, amount = 2) {
if (val === null || val === '' || val === undefined) return '';
let arr = String(val).split('.');
if (arr[1]) {
let zero = '';
let len = arr[1].length;
if (len < amount) {
for (let i = 0; i < amount - len; i++) {
zero += '0';
}
return arr[0] + '.' + arr[1].slice(0, amount) + zero;
}
return arr[0] + '.' + arr[1].slice(0, amount)
}
return parseFloat(val).toFixed(amount);
},
/**
* AES 加密和解密 -----------------------------------------
* import CryptoJS from 'crypto-js'
* 使用 AES.encrypt(oldPassword,'absoietlj32fai12');
*/
encrypt(word, keyStr) {
keyStr = keyStr ? keyStr : "absoietlj32fai12";
let key = CryptoJS.enc.Utf8.parse(keyStr);
let srcs = CryptoJS.enc.Utf8.parse(word);
let encrypted = CryptoJS.AES.encrypt(srcs, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
},
//解密
decrypt(word, keyStr) {
keyStr = keyStr ? keyStr : 'absoietlj32fai12';
var key = CryptoJS.enc.Utf8.parse(keyStr);//Latin1 w8m31+Yy/Nw6thPsMpO5fg==
var decrypt = CryptoJS.AES.decrypt(word, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
return CryptoJS.enc.Utf8.stringify(decrypt).toString();
},
/**
* AES 加密和解密 -----------------------------------------
*/
/**
* 获取滚动条高度
*/
getScrollTop() {
let scroll_top = 0;
if (document.documentElement && document.documentElement.scrollTop) {
scroll_top = document.documentElement.scrollTop;
} else if (document.body) {
scroll_top = document.body.scrollTop;
}
return scroll_top;
},
/**
* 导出 .doc | .xlsx | .docx
*/
printBlob(res, type, name) {
let fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
// 0: .doc 1: .xlsx 2 .docx
if (type == 0) {
fileType = 'application/msword'
} else if (type == 1) {
fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
} else if (type == 2) {
fileType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=UTF-8'
}
let blob = new Blob([res], { type: fileType }); //规定文件类型 res就是返回你的数据流了
let link = document.createElement('a');
// link.download = fileName//a标签添加属性
let objectUrl = URL.createObjectURL(blob);
link.setAttribute("href", objectUrl);
link.setAttribute("download", name);
link.click();
/*
释放内存:
URL.revokeObjectURL()方法会释放一个通过URL.createObjectURL()创建的对象URL.
当你要已经用过了这个对象URL,然后要让浏览器知道这个URL已经不再需要指向对应的文件的时候,
就需要调用这个方法.
*/
window.URL.revokeObjectURL(link.href)
},
/**
* 过滤无效的数值
* @param {Number} val 数值
* @returns {Number|String} 返回数值|字符串
*/
numFilter(val) {
if (val === null || val === '--') return '--';
return val;
},
/**
* 修改字体大小 rem
*/
rem() {
let htmlW = document.documentElement.clientWidth; // html的宽度
let bodyW = document.body.clientWidth; // body宽度
let w = htmlW | bodyW; // 兼容ie,屏幕宽度
// 100px = 1rem
document.documentElement.style.fontSize = (w / 750 * 100) + 'px';
},
/**
* 生成指定数目和范围的随机数
* @param {Number} min 最小数字
* @param {Number} max 最大数字
* @param {Number} countNum 指定数目
* @returns {Number|Array} 返回数值(不包括 max )
*/
rangeRandomNum(min, max, countNum) {
if (countNum) {
let arr = [];
for (let i = 0; i < countNum; i++) {
let n = Math.floor(Math.random() * (max - min)) + min;
if (arr.indexOf(n) == -1) arr.push(n);
}
return arr;
}
return Math.floor(Math.random() * (max - min)) + min;
},
/**
* 是否为正整数
* @param {String|Number} s 数字
* @returns {Boolean} 返回 true | false
*/
isPositiveNum(s) {
let re = /^[0-9]*[1-9][0-9]*$/;
return re.test(s);
},
/**
* 格式化数值(默认等于超过 10000 显示如:1W,1W+ 的格式)
* @param {String|Number} n 正整数数值
* @param {String|Number} quantity 保留多少位小数(默认:1)
* @returns {String|Number} 返回数字
*/
formatTenThousand(n, quantity, digits) {
n = parseInt(n);
quantity = quantity || 1;
digits = digits || 10000;
if (n < digits) return n;
if (n == digits) return '1W';
let num = Number(n) / 10000;
let integer = String(num).split('.')[0]; // 整数部分
let decimal = String(num).split('.')[1]; // 小数部分
let decimalAmount = decimal.substr(0, quantity) // 小数多少位
return integer + '.' + decimalAmount + 'W+';
// n = parseInt(n);
// digit = digit || 1;
// if (n < 10000) return n;
// let num = Number(n) / 10000;
// let re = /^[0-9]*[1-9][0-9]*$/;
// // 是否是正整数
// if (re.test(n)){
// return num.toFixed(digit) + 'W+'
// // return num + 'W';
// }
// if (num > 1) return num.toFixed(digit) + 'W+';
// return n;
},
/**
* 判断是否是【闰年】
* @param {String|Number} year 年份
* @returns {Boolean} 返回 true | false
*/
isLeapYear(year) {
let flag = false;
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
flag = true;
}
return flag;
},
/**
* 编码/解码
* @param {Any} target 要编码的目标
* @param {Boolean} type true 编码(默认);false 解码
* @returns {Array} 返回一个保留 digit 位的小数
*/
encodedDecode: function (target, type) {
if (type) {
// 编码
return encodeURIComponent(JSON.stringify(target));
} else {
// 解码
return JSON.parse(decodeURIComponent(target))
}
},
/**
* 数组降维
* @param {Array} arr 要降维的数组
* @returns {Array} 返回一个新数组
* 也可用 ES6 中,数组方法 flat()
*/
reduceArray: function (arr) {
let newArr = [];
// begin: 传入的newArr, current: 当前值
arr.reduce((begin, current) => {
Array.isArray(current) ?
begin.push(...arguments.callee(current)) :
begin.push(current);
return begin
}, newArr);
return newArr;
// 方式二(递归):
// var result = [];
// arr.forEach(function (item) {
// if (Array.isArray(item)) {
// result = result.concat(flatten(item));
// } else {
// result.push(item);
// }
// });
// return result;
},
/***
* 格式化数字,按千位逗号分隔
* @param {Number|String} num 数值
* @param {Boolean} decimal 保留多少位小数(默认:2)
* @return {String} 返回格式化后的数值字符串
*/
formatNumber: function (num, decimal = 2) {
let temp = '';
if (num == '0.00') return '0.00';
if (num == 0) return 0;
if (num == null || num == '') return '';
if (num.toString().indexOf('.') > -1) {
let n = parseFloat(num).toFixed(decimal);
temp = n.toString().split('.');
if (temp[1]) {
return temp[0].replace(/(\d)(?=(\d{3})+$)/g, '$1,') + '.' + (temp[1] || '00');
} else {
return temp[0].replace(/(\d)(?=(\d{3})+$)/g, '$1,')
}
} else {
return num.toString().replace(/(\d)(?=(\d{3})+$)/g, '$1,');
}
// 将浮点数点左边的数每三位添加一个逗号
// return number.toLocaleString('en')
// let temp = '';
// if(num.toString().indexOf('.') > -1){
// temp = num.toString().split('.');
// return temp[0].replace(/(\d)(?=(\d{3})+$)/g,'$1,') + '.' + (temp[1] || '00');
// }else{
// return num.toString().replace(/(\d)(?=(\d{3})+$)/g,'$1,');
// }
// return temp;
},
/***
* 判断是否为对象或数组,且不能为 null
* @param {Object|Array} obj 传入的对象或数组
* @return {Boolean} 返回 true | false
*/
isObject: function (obj) {
return typeof obj === 'object' && obj !== null;
},
/***
* 不能为负数,最多保留两位小数
* @param {Number|String} num 传入的数字
* @return {Boolean} 返回 true | false
*/
notLossTowDecimals: function (num) {
let reg = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/;
return reg.test(num)
},
/***
* 保留多少位小数(百分比也可传入:'33.3333333333304%' )
* @param {Number|String} num 传入的数值
* @param {Number|String} digit 需要保留多少位小数(默认:2)
* @return {Number|String} 返回数字或字符串数字或字符串百分比
*/
formatFloat: function (num, digit) {
digit = digit || 2;
let reg = /%/g;
if (num === null || num === '--') return '--';
if (reg.test(num)) {
return Number(num.split('%')[0]).toFixed(digit) + '%';
}
return Number(num).toFixed(digit);
},
/**
* 小数位四舍五入(百分比不行)
* @param {Number} num 要格式化的数值
* @param {Number} digit 表示保留多少位小数
* @returns {Number} 返回一个保留 digit 位的小数
*/
formatFloat2: function (num, digit) {
let pow = Math.pow(10, digit); // 表示保留多少位小数
return (Math.round(num * pow) / pow).toFixed(digit);
},
/***
* 获取两个数组中不共有的元素
* @param {Array} a1 传入的数组
* @param {Array} a2 传入的数组
* @param {String} prop 根据那个元素对象的属性进行获取
* @return {Array} newArr 返回一个新数组
* 【注意:a2 的元素必须都是能在 a1 中找到】
*/
getDiffElement: function (a1, a2, prop) {
let arr1 = a1, arr2 = a2;
if (a1.length < a2.length) {
arr1 = a2;
arr2 = a1;
}
// 获取两个数组中不共有的对象
if (prop) {
let newArr = [];
arr1.forEach((v1, i1, a1) => {
let boo = false;
arr2.forEach((v2, i2, a2) => {
if (v1[prop] == v2[prop]) boo = true;
});
if (!boo) {
newArr.push(v1);
}
});
return newArr;
}
let newArr1 = [], newArr2 = [];
newArr1 = arr1.filter(item => {
return !arr2.includes(item)
});
newArr2 = arr2.filter(item => {
return !arr1.includes(item)
});
return [].concat(newArr2, newArr1);
},
/***
* 获取两个数组中共有的元素
* @param {Array} arr1 传入的数组
* @param {Array} arr2 传入的数组
* @param {String} prop 根据那个元素对象的属性进行获取
* @return {Array} newArr 返回一个新数组
* 【注意:arr2 的元素必须都是能在 arr1 中找到】
*/
intersection: function (arr1, arr2, prop) {
let newArr = [];
arr1.forEach(item => {
arr2.forEach(val => {
if (prop && item[prop] == val[prop]) {
newArr.push(item);
} else if (item == val) {
if (item == val) newArr.push(item);
}
});
});
return newArr;
},
/***
* 根据指定格式返回【日期对象】
* @param {time, format, type}
* date: 获取的时间(一定是Date对象)
* format: 日期返回格式(默认为 '-')
* type: 选择返回年月日(date)或时分秒(time)或两种都有(默认:all)
* @return {Date} 返回【日期对象】
*/
setDateObj(time, format, type) {
type = type || 'all';
format = format || '-';
let dateStrs = [];
let timeStrs = [];
let date = new Date();
if (type == 'date') {
if (!time) {
throw Error(`The parameter format requires "yy-mm-dd", but the obtained parameter is ${time}`);
}
dateStrs = time.split(format);
date.setFullYear(dateStrs[0]); // 设置某一年
date.setMonth(dateStrs[1] - 1); // 设置某个月
date.setDate(dateStrs[2]); // 设置某一天
} else if (type == 'time') {
if (!time) {
throw Error(`The parameter format requires "hh-mm-ss", but the obtained parameter is ${time}`);
}
timeStrs = time.split(':');
date.setHours(timeStrs[0]); // 设置小时
date.setMinutes(timeStrs[1]); // 设置分钟
date.setSeconds(timeStrs[2]); // 设置秒
} else if (type == 'all') {
let text = `The parameter format requires "yy-mm-dd hh-mm-ss", but the obtained parameter is ${time}`
let timeArr = time.split(' ');
if (!timeArr[0]) throw Error(text);
if (!timeArr[1]) throw Error(text);
dateStrs = timeArr[0].split(format);
timeStrs = timeArr[1].split(':');
date.setFullYear(dateStrs[0]); // 设置某一年
date.setMonth(dateStrs[1] - 1); // 设置某个月
date.setDate(dateStrs[2]); // 设置某一天
date.setHours(timeStrs[0]); // 设置小时
date.setMinutes(timeStrs[1]); // 设置分钟
date.setSeconds(timeStrs[2]); // 设置秒
}
return date;
},
/***
* 根据Date对象或Date字符串 拆分为对象
* @param {Date} date 获取的Date对象 | Date字符串(2022-4-1 12:12:12)
* @param {String} format 根据年月日格式拆分字符串(默认为 '-')
* @param {String} calendar 选择返回年月日或时分秒或两种都有
* @return {Object} 返回对象
* { year, month, day, hour, minutes, seconds }
*/
splitDate(date, format, calendar) {
calendar = calendar || 'all';
format = format || '-';
let year, month, day, hour, minutes, seconds;
if (typeof date == 'string') {
let timeStr = [], dateStr = [], timeArr = [],
dateArr = [], timeAll = [];
if (date.indexOf(" ") == -1) {
if (date.indexOf(":") == -1) {
dateStr = date.split(format); // 年月日数组
} else {
timeStr = date.split(':'); // 时分秒数组
}
} else {
timeAll = date.split(' ');
timeArr = timeAll[1];
dateArr = timeAll[0];
timeStr = timeArr.split(':'); // 时分秒数组
dateStr = dateArr.split(format); // 年月日数组
}
return {
year: dateStr[0], // 年
month: dateStr[1], // 月
day: dateStr[2], // 日
hour: timeStr[0], // 时
minutes: timeStr[1], // 分
seconds: timeStr[2] // 秒
}
}
if (calendar == 'date') {
// 只要--年月日
year = date.getFullYear();
month = date.getMonth() + 1;
day = date.getDate();
} else if (calendar == 'time') {// 只要--时分秒
hour = date.getHours();
minutes = date.getMinutes();
seconds = date.getSeconds();
} else {
year = date.getFullYear();
month = date.getMonth() + 1;
day = date.getDate();
hour = date.getHours();
minutes = date.getMinutes();
seconds = date.getSeconds();
}
return { year, month, day, hour, minutes, seconds }
},
/***
* 根据指定格式返回【日期字符串】
* @param {Date|String} date 获取的Date对象或时间字符串
* @param {String} format 设置年月日返回格式(默认为 '-')
* @param {String} calendar 选择返回年月日或时分秒或两种都有
* @param {String} isZhCn 中文格式;true中文
* @return {String|Object} 返回指定格式的【日期字符串】
* 扩展:
* 返回以"-"方式的年月日:
* new Date().toISOString().slice(0, 10)
*/
getDate(date, format, calendar, isZhCn) {
calendar = calendar || 'all';
isZhCn = isZhCn || false;
format = format || '-';
// 如果传入的 date 参数是 Date 对象 ------------------------
let year = '', month = '', day = '', hour = '', minutes = '',
seconds = '';
// 不足两位数,补0
let fillZero = (n) => {
let str = n < 10 ? '0' + n : n;
return str;
}
if (calendar == 'date') {
// 只要--年月日
year = date.getFullYear();
month = fillZero(date.getMonth() + 1);
day = fillZero(date.getDate());
if (isZhCn) {
return `${year + '年' + month + '月' + day + '日'}`
}
return year + format + month + format + day;
} else if (calendar == 'time') {
// 只要--时分秒
hour = fillZero(date.getHours());
minutes = fillZero(date.getMinutes());
seconds = fillZero(date.getSeconds());
return `${hour}:${minutes}:${seconds}`
} else {
// 全部--年月日 时分秒
year = date.getFullYear();
month = fillZero(date.getMonth() + 1);
day = fillZero(date.getDate());
hour = fillZero(date.getHours());
minutes = fillZero(date.getMinutes());
seconds = fillZero(date.getSeconds());
if (isZhCn) {
return `${year + '年' + month + '月' + day + '日'} ${hour}:${minutes}:${seconds}`
}
return `${year + format + month + format + day} ${hour}:${minutes}:${seconds}`
}
},
/***
* 给一周的数组排序(如:["星期一","星期二","星期三","星期四","星期五","星期六","星期日"])
* @param {Array} weeks 传入的周数组
* @return {Array} 返回排好序的数组(升序)
*/
sortWeeks(weeks) {
var _weeks = [];//创建临时排序的数组
for (var i = 0; i < weeks.length; i++) {
if (weeks[i] == "星期一") {
var _week = {};
_week["id"] = 1;
_week["name"] = "星期一";
_weeks.push(_week);
}
if (weeks[i] == "星期二") {
var _week = {};
_week["id"] = 2;
_week["name"] = "星期二";
_weeks.push(_week);
}
if (weeks[i] == "星期三") {
var _week = {};
_week["id"] = 3;
_week["name"] = "星期三";
_weeks.push(_week);
}
if (weeks[i] == "星期四") {
var _week = {};
_week["id"] = 4;
_week["name"] = "星期四";
_weeks.push(_week);
}
if (weeks[i] == "星期五") {
var _week = {};
_week["id"] = 5;
_week["name"] = "星期五";
_weeks.push(_week);
}
if (weeks[i] == "星期六") {
var _week = {};
_week["id"] = 6;
_week["name"] = "星期六";
_weeks.push(_week);
}
if (weeks[i] == "星期日") {
var _week = {};
_week["id"] = 7;
_week["name"] = "星期日";
_weeks.push(_week);
}
}
_weeks.sort(function (a, b) { return a.id - b.id; });
//将weeks清空并将排序好的值赋给weeks
weeks = [];
for (var i = 0; i < _weeks.length; i++) {
weeks.push(_weeks[i].name);
}
return weeks;
},
/***
* 根据指定的属性,将对象进行分组
* @param {Array} arr 传入的数组
* @param {String} key 要根据对象中的哪个属性进行分组
* @returns {Array} 返回数组
*/
grouping: function (arr, key) {
// 方法1:根据对象属性的唯一性
let groups = {}
arr.forEach(item => {
let group = item[key]; // 获取属性的值
groups[group] = groups[group] || [];
groups[group].push(item);
})
return Object.keys(groups).map(item => {
return groups[item]
})
// 方法2:
// var _arr = [],
// _t = [],
// // 临时的变量
// _tmp;
// // 按照特定的参数将数组排序将具有相同值得排在一起
// arr = arr.sort(function (a, b) {
// var s = a[key],
// t = b[key];
// return s < t ? -1 : 1;
// });
// if (arr.length) {
// _tmp = arr[0][key]; // 数组第一个对象的属性值
// }
// // 将相同类别的对象添加到统一个数组
// for (var i in arr) {
// if (arr[i][key] === _tmp) {
// _t.push(arr[i]);
// } else {
// _tmp = arr[i][key];
// _arr.push(_t);
// _t = [arr[i]];
// }
// }
// // 将最后的内容推出新数组
// _arr.push(_t);
// return _arr;
},
/**
* 获取元素在数组中的下标, 如果元素为对象,则根据对象 唯一字段 获取
* @param {Array} arr 传入的数组
* @param {Number|String|Object} obj 传入的数字或对象
* @param {String} key 传入的元素对象字段名; 传入的字段名要数组中的所有元素都拥有
* @returns 如果没有找到,则返回 -1;
如果在数组中没有找到元素对象的字段名,则返回 undefined
注意:数组中的所有元素对象的格式要一致, 如:
[ {id:1, name:Tom}, {id:2, name: Jack} ]
*/
getArrIndex: function (arr, obj, key) {
var len = arr.length;
if (obj instanceof Object) {
while (len--) {
if (arr[len][key]) {
if (arr[len][key] == obj[key]) {
return len;
}
} else {
return undefined;
}
}
} else {
while (len--) {
if (arr[len] == obj) {
return len;
}
}
}
return -1;
},
/**
* 字符串首字母大写
* @param {String} str
* @returns
*/
firstCapitalLetters: function (str) {
return str.charAt(0).toUpperCase() + str.slice(1);
},
/**
* 去除空格
* @param {*} str 字符串
* @param {*} s 左 | 右 | 左右 | 所有 空格
* @returns
*/
rmSpace: function (str, s) {
s = s || 'all';
if (s == 'all') {
return str.replace(/\s+/g, '');
} else if (s == 'left') {
return str.replace(/^\s*/, '');
} else if (s == 'right') {
return str.replace(/(\s*$)/g, '');
} else if (s == 'about') {
return str.replace(/^\s+|\s+$/g, '');
}
},
/**
* 将字符串转换成二进制形式,中间用空格隔开
* @param {String|Array} obj 字符串或数组
* @return {String|Array}
*/
strToBinary: function (obj) {
var result = [];
var list;
if (Object.prototype.toString.call(obj) == '[object String]') {
list = obj.replace(/\s+/g, '').split(''); // 去除空格,并分割为字符串数组
} else {
list = obj;
}
for (var i = 0; i < list.length; i++) {
if (i != 0) {
result.push(' ');
}
var item = list[i];
var binaryStr = item.charCodeAt().toString(2);
result.push(binaryStr);
}
return result.join('');
},
/**
* 将二进制字符串转换成 Unicode 字符串
* @param {String|Array} obj 字符串或数组
* @return {String|Array}
*/
binaryToStr: function (obj) {
var result = [];
var list = [];
if (Object.prototype.toString.call(obj) == '[object String]') {
list = obj.split(' ');
} else {
list = obj;
}
for (var i = 0; i < list.length; i++) {
var item = list[i];
var asciiCode = parseInt(item, 2);
var charValue = String.fromCharCode(asciiCode);
result.push(charValue);
}
return result.join("");
},
/**
* 导出 excel 表格
* @param {String} FileName 文件名称
* @param {String} TableHtml 表格
* @param {String} css 样式
*/
ExcelExportLdc: function (FileName, TableHtml, css) {
var templet = `
<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet>
<x:Name>${'worksheet1'}</x:Name>
<x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>
</x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->
<style type="text/css">
${css || ''}
</style>
</head>
<body>${TableHtml}</body>
</html>
`
// console.log(templet)
// base64
var base64 = function (s) {
return window.btoa(unescape(encodeURIComponent(s)))
}
// 点击下载
var a = document.createElement('a');
a.href = 'data:application/vnd.ms-excel;base64,' + base64(templet)
a.download = FileName + ".xls";
a.click();
},
/**
* base64 加密
* @param {} s
* 解密:window.atob()
*/
base64: function (s) {
return window.btoa(unescape(encodeURIComponent(s)))
},
/**
* 获取用户当前 ip 地址或当前地址(省,市) --- jq写法
* @param {Boolean} boo :
* false 获取用户当前 ip 地址;true 获取用户当前 ip 地址和当前地址(省,市)
* @param {Function} callback 回调函数
* @returns
* 注意:使用该方法前,先引入 jquery.js
* 也可以直接在页面添加:
* <script src="https://pv.sohu.com/cityjson?ie=utf-8"></script>
* <script src="https://ip.ws.126.net/ipquery"></script>
* 这样可以直接使用 returnCitySN, localAddress 变量
*/
getIpProvinceCity_JQ: function (boo, callback) {
var obj;
if (boo) {
$.getScript('https://pv.sohu.com/cityjson?ie=utf-8', function () {
$.getScript('https://ip.ws.126.net/ipquery', function () {
obj = {
returnCitySN: returnCitySN,
localAddress: localAddress
}
callback(obj)
})
})
} else {
$.getScript('https://pv.sohu.com/cityjson?ie=utf-8', function () {
obj = returnCitySN;
callback(obj)
})
}
},
/**
* 获取浏览器类型
* @param {}
* @returns {String} browser 浏览器类型
*/
getBrowser: function () {
var userAgent = window.navigator.userAgent; // 获取浏览器
var browser;
// Firefox
if (userAgent.indexOf('Firefox') !== -1) {
browser = 'Firefox'
}
// Edge
if (userAgent.indexOf('Edge') !== -1) {
browser = 'Edge'
}
// IE浏览器
if (userAgent.match(/msie ([\d.]+)/)) {
browser = 'IE'
}
// Chrome浏览器
if (userAgent.match(/Chrome\/([\d.]+)/)) {
browser = 'Chrome'
}
// safari
if (userAgent.match(/Version\/([\d.]+).*Safari/)) {
browser = 'Safari'
}
// opera
if (userAgent.match(/Opera.([\d.]+)/)) {
browser = 'Opera'
}
return browser;
},
//用 js 原生写法: ajax
ajax: function (url, callback) {
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest(); //IE7+,Firefox,Chrome,Safari,Opera
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP"); //IE5,6
}
//发送异步请求
xhr.open("GET", url, true);
//发送请求
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr)
//获取服务器响应
callback(xhr.responseText)
}
};
},
/**
* 根据指定个数分割数组(伪数组不行)
* @param {Array} array 数组
* @param {Number} subNum 以 subNum 个元素为一个数组拆分
* @returns {Array}
*/
group: function (array, subNum) {
let index = 0;
let newArray = [];
while (index < array.length) {
newArray.push(array.slice(index, index += subNum));
}
return newArray;
},
/**
* 根据指定个数分割数组(伪数组也可以传进)
* @param {Array} arr 数组
* @param {Number} size 以 size 个为一个数组进行分割
* @return {Array} 返回一个新数组,新数组里面是以size个为一个的数组
*/
chunkArr: function (arr, size) {
var myArr;
//判断如果没有 length,或者size没有传值,size小于1,就返回空数组
if (!arr.length || !size || size < 1) return [];
if (!Array.isArray(arr)) {
myArr = Array.from(arr);
} else {
myArr = arr;
}
let start = null, end = null, result = [];
for (let i = 0; i < Math.ceil(myArr.length / size); i++) {
start = i * size;
end = start + size;
result.push(myArr.slice(start, end))
}
return result;
},
/**
* 获取 url 地址栏 ? 后面的参数
* @param {}
* @param {}
* @returns {Object}
*/
getUrl: function () {
var url = window.location.search; // 获取从 ? 后面开始的 url
var myObj = {};
if (url.indexOf('?') != -1) {
var arr = url.substr(1).split('&')
arr.forEach(item => {
var temp = item.split('=')
myObj[temp[0]] = decodeURI(temp[1])
})
}
return myObj
},
/**
* 获取地址栏 ? 后面指定的参数的值
* @param {String} strName 指定参数
* @returns
*/
getUrlSpecify: function (strName) {
var strHref = document.location.toString();
var intPos = strHref.indexOf("?");
var strRight = strHref.substr(intPos + 1); // 获取到右边的参数部分
var arrTmp = strRight.split("&"); // 以&分割成数组
for (var i = 0; i < arrTmp.length; i++) { // 循环数组
var dIntPos = arrTmp[i].indexOf("=");
var paraName = arrTmp[i].substr(0, dIntPos);
var paraData = arrTmp[i].substr(dIntPos + 1);
if (paraName == strName) {
return decodeURI(paraData);
}
}
return "";
},
/**
* 对象混合
* @param {Object} obj1
* @param {Object} obj2
* 返回一个新对象
*/
mixin: function (obj1, obj2) {
var newObj = {};
// 复制obj2的属性
for (var prop in obj2) {
newObj[prop] = obj2[prop];
}
// 找到obj1中有而obj2中没有的属性
for (var prop in obj1) {
if (!(prop in obj2)) {
newObj[prop] = obj1[prop];
}
}
return newObj;
},
/**
* 对象克隆(复制)
* @param {Object} target 克隆对象
* @param {Boolean} deep 是否深度克隆
* @return {Array|Object} 返回一个新数组或新对象
*/
clone: function (target, deep) {
if (Array.isArray(target)) {
if (deep) {
// 深度克隆
let newArr = [];
for (let i = 0; i < target.length; i++) {
if (Object.prototype.hasOwnProperty.call(target, i)) {
newArr.push(arguments.callee(target[i], deep));
}
}
return newArr;
}
return target.slice();
} else if (Object.prototype.toString.call(target) === "[object Object]") {
let newObj = {};
for (let prop in target) {
// 是否是自身的属性
if (Object.prototype.hasOwnProperty.call(target, prop)) {
if (deep) {
// 深度克隆
newObj[prop] = arguments.callee(target[prop], deep);
} else {
newObj[prop] = target[prop];
}
}
}
return newObj;
} else {
// 原始类型
return target; // 递归函数的终止条件
}
},
/**
* 函数防抖
* 通过setTimeout 的方式,在一定的时间间隔内,将多次触发变成一次触发
* @param {Object} target 目标对象
* @param {Function} fn 回调函数
* @param {Number} delay 时间
* @param {Boolean} isOne true(默认) 只执行1次;false 执行第一次和最后一次
* 补充:isOne为false时,只点击一次的时候立即执行。当点击多次时第一次和最后一次执行。
*/
debounce: function (target, fn, delay = 500, isOne = true) {
delay = delay || 500;
if (typeof target == 'function') {
fn = target;
target = this;
}
if (isOne) { // ---------- 只执行一次 ----------
// 如果定时器存在清空定时器
if (target.timeOutId) cleartimeOutIdout(target.timeOutId);
target.timeOutId = setTimeout(() => {
fn(); // arguments 是获取 return 这个函数的参数
}, delay);
} else { // ---------- 执行第一次和最后一次 ----------
//定义一个firstClick,判断是否第一次执行,初始值为true
var firstClick = !target.timeOutId;
//第一次会立即执行
if (firstClick) {
fn();
}
// 如果定时器存在清空定时器
if (target.timeOutId) {
clearTimeout(target.timeOutId);
}
// 设置定时器,此时firstClick会变为false,规定时间后timeOutId才会为null
target.timeOutId = setTimeout(() => {
target.timeOutId = null;
// 如果firstClick为true,执行;点击多次时,最后一次执行。
if (!firstClick) {
fn();
}
}, delay);
}
},
/**
* 函数节流:
* 减少一段时间的触发频率(间隔时间执行)
* @param {Function} callback 回调函数
* @param {Number} time 规定时间
* @param {Boolean} immediately 值为true, 则使用时间戳的写法; 值为false, 则使用定时器的写法。
*/
throttle: function (callback, time, immediately) {
if (immediately === undefined) immediately = true; // immediately没有传值时,默认为 true
if (immediately) {
// 写法1:第一次立即触发,下一次后等规定的时间触发
var t;
return function () {
if (!t || Date.now() - t >= time) { // 之前没有计时 或 距离上次执行的时间已超过规定的时间
callback.apply(null, arguments);
t = Date.now(); // 得到的时间戳
}
}
} else {
// 写法2:第一次等规定的时间触发
var timer;
return function () {
if (timer) {
return;
}
var args = arguments; // 利用闭包,保持参数数组
timer = setTimeout(function () {
callback.apply(null, args);
timer = null;
}, time);
}
}
},
/**
* 判断数据类型
* @param {Object} target 目标对象。没有传参时, 返回 Undefined
* 注意:该方法最后返回如:
* String, Number, Boolean, Undefined, Null, Symbol
* Array, Object, Function, RegExp, 等等...
*
* 如果不用该方法,可以直接使用 Object.prototype.toString.call(参数), 返回值是一个字符串;
* 但是,与其返回值对比的格式是:
* "[object, Number]" "[object, String]" "[object, Boolean]"
* "[object, Undefined]" "[object, Symbol]" "[object, Null]"
* "[object, Array]" "[object, Object]" "[object, Function]"
* 等等...
*/
dataType: function (target) {
var str = Object.prototype.toString.call(target);
var pattern = /\s[a-z]+/gi;
return str.match(pattern)[0];
},
/**
* 圣杯模式继承
* 注意:顺序很重要!!! 一定是调用该方法之后,才 new 出一个对象
* @param {Object} Target 目标对象
* @param {Object} Origin 源对象
*/
inherit: (function () {
var F = function () { };
return function (Target, Origin) {
F.prototype = Origin.prototype;
Target.prototype = new F();
Target.prototype.constructor = Target;
// 超类:找到真正继承的
Target.prototype.uber = Origin.prototype;
}
}()),
/**
* 数组排序
* @param {Array} arr 数组
* @param {Boolean} boo false: 升序(默认); true: 降序
* 升序:a - b
* 降序:b - a
*/
mySort: function (arr, boo) {
boo = boo || false;
if (boo) {
arr.sort(function (a, b) {
return b - a; // 降序
});
} else {
arr.sort(function (a, b) {
return a - b; // 升序
});
}
},
/**
* 数组去重
* @param {Array} arr 数组
* 不用该方法,也可以用双重for循环 || ES6的 Set 构造函数
* @return {Array} 返回新数组
*/
unique: function (arr) {
// var temp = {}, newArr = [], length = arr.length;
// for(var i = 0; i < length; i++){
// if(!temp[arr[i]]){
// temp[arr[i]] = '???'; // 占位
// newArr.push(arr[i]);
// }
// }
// return newArr;
// 方式2:
// let newArr = []
// for (let i = 0; i < arr.length; i++) {
// if (!newArr.includes(arr[i])) {
// newArr.push(arr[i])
// }
// }
// return newArr;
// 方式3:
// let newArr = []
// for(let i = 0; i < arr.length; i++) {
// if(newArr.indexOf(arr[i]) < 0) {
// newArr.push(arr[i])
// }
// }
// return newArr;
// 方式4:
let res = {};
arr.forEach(item => {
if (!res[item]) res[item] = item;
})
return Object.values(res);
},
/**
* 数组里的对象去重并合并
* @param {Array} arr 数组
* @param {String} prop 对象属性
* @returns
*/
uniqueMerge: function (arr, prop) {
let newArr = [];
arr.forEach(function (item) {
let hasPush = false;
newArr.forEach((item2, index, thisArr) => {
if (item[prop] == item2[prop]) {
hasPush = true;
thisArr[index] = { ...item, ...item2 };
return;
}
});
if (!hasPush) {
newArr.push(item);
}
});
return newArr;
},
/**
* json 数据转 xml 或 xml 数据转 json
* @param {*} data 传入的 xml 或 json 数据;传入 json 数据时,最好以对象的形式传入
* 拓展 --> 匹配xml格式:^<[^/]\S+?>.*$
* 【【 注意:调用该方法,需要先引入 xml2json.js,否则创建 X2JS 对象失败 】】
* 参考网址:https://www.hangge.com/blog/cache/detail_1798.html
*/
conversionFormatX2JS: function (data) {
var x2js = new X2JS();
var newData;
// 判断数据类型
var dataType = function (target) {
return Object.prototype.toString.call(target);
}
if (dataType(data) == '[object String]') { // xml 转 json
newData = x2js.xml_str2json(data);
if (!newData) throw new Error('请确认传入数据是否是"xml"格式');
} else if (dataType(data) == '[object Object]') {
newData = x2js.json2xml_str(data);
} else if (dataType(data) == '[object Array]') {
newData = x2js.json2xml_str({
array: data
});
} else {
newData = data;
}
return newData;
},
/**
* 判断是否是微信浏览器
* @return {Boolean}
*/
isWeiXin: function () {
var ua = window.navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == 'micromessenger') {
return true; // 微信端
} else {
return false;
}
},
/**
* 创建DOM对象, 并且添加属性,返回新创建的元素
* @param {String} nodeName 创建的新元素名(必填)
* @param {Element} parentNode 被插入的父元素; 默认插入到 body
* @param {String} param 创建的新元素的属性对象
* @return {Element} el 返回新创建的元素
* 注意:自定义属性要带有 data- ,会被添加到行内中,即添加到元素属性 dataset 对象中;
* 否则,直接给元素添加属性
*/
createElement: function (nodeName, parentNode, param) {
var el = document.createElement(nodeName);
for (var prop in param) {
if (Object.prototype.toString.call(param[prop]) == '[object Function]') {
el.addEventListener(prop, param[prop]);
} else if (prop == 'class') {
el.classList.add(param[prop]);
} else if (prop.indexOf('data-') > -1) {
el.setAttribute(prop, param[prop]);
} else {
el[prop] = param[prop];
}
}
if (parentNode) {
parentNode.appendChild(el);
} else {
document.body.appendChild(el);
}
return el;
},
/**
* 获取获取在元素中的位置
* @param {String} id 元素id
*/
getMousePositionInElement(id) {
const element = document.getElementById(id);
element.addEventListener('mousemove', (event) => {
const rect = element.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
console.log(`Mouse position in element: (${x}, ${y})`);
});
},
/**
* 获取元素在浏览器中的位置(让元素相对于浏览器定位才能获取)
* @param {Object} el DOM 元素
* @returns
* 注意:offsetLeft/Top 元素左上角相对父元素左上角的距离
所以,要获取到元素在浏览器中的位置,请保持元素的祖先元素不是定位元素
扩展:
获取鼠标在元素中的坐标:
x = 鼠标坐标e.pageX - 元素在浏览器中的坐标offsetLeft
y = 鼠标坐标e.pageY - 元素在浏览器中的坐标offsetTop
*/
getElePlace: function (el) {
return {
offsetLeft: el.offsetLeft,
offsetTop: el.offsetTop
}
},
/**
* 获取滚动条滚动的距离
*/
getScrollOffset: function () {
if (window.pageXOffset) {
return {
x: window.pageXOffset,
y: window.pageYOffset
}
} else {
return {
x: document.body.scrollLeft || document.documentElement.scrollLeft,
y: document.body.scrollTop || document.documentElement.scrollTop
}
}
},
/**
* 获取浏览器可视区域大小
*/
getViewportOffset: function () {
if (window.innerWidth) {
return {
w: window.innerWidth, // 包括滚动条width
h: window.innerHeight
}
} else {
if (document.compatMode == 'BackCompat') { // 怪异模式
return {
w: document.body.clientWidth, // 不包括滚动条width
h: document.body.clientHeight
}
} else { // 标准模式
return {
w: document.documentElement.clientWidth, // 不包括滚动条width
h: document.documentElement.clientHeight
}
}
}
},
/**
* 获取当前元素所有最终使用的CSS属性值
* @param {Element} el 当前元素对象(必填)
* @param {String} pseudoEl 当前元素的伪元素
* @param {String} prop 当前元素或当前元素的伪元素的属性名
* 注意:因为保留字的原因,传入的 float 属性名,可以用 cssFloat 代替; IE 8 支持的是 styleFloat
* IE 的 currentStyle属性不支持伪类样式的获取
*/
getStyle: function (el, pseudoEl, prop) {
pseudoEl = pseudoEl || null;
if (window.getComputedStyle) {
if (prop) {
return window.getComputedStyle(el, pseudoEl)[prop];
} else {
return window.getComputedStyle(el, pseudoEl);
}
} else {
if (prop) {
return el.currentStyle[prop];
} else {
return el.currentStyle;
}
}
},
/* 未完善 =========================================================================================== */
/**
* 禁用复制粘贴:默认整个页面禁用复制粘贴剪切
* @param {Element} el 'Dom 对象'
* @param {Object} param 一个对象
* selectstart:禁用选择,防止复制;
* paste:禁用粘贴
* copy:禁用复制
* cut:禁用剪切,防止复制
* @param {Function} callback 回调函数:禁用剪切,禁用复制
*
*/
disableCopyPaste: function (el, param, callback) {
param = Object.assign({}, {
selectstart: false,
paste: false,
copy: false,
cut: false
}, param);
callback = callback || function () { };
// 禁用选择,防止复制
var selectstart = function () {
return param.selectstart;
}
// 禁用粘贴
var paste = function () {
return param.paste;
}
// 禁用复制
var copy = function () {
callback();
return param.copy;
}
// 禁用剪切,防止复制
var cut = function () {
callback();
return param.cut;
}
if (!el || el instanceof HTMLBodyElement) {
console.log('body')
var body = document.body || document.documentElement;
body.onselectstart = selectstart;
body.onpaste = paste;
body.oncopy = copy;
body.oncut = cut;
} else if (el instanceof Element) {
console.log('element')
el.onselectstart = selectstart;
el.onpaste = paste;
el.oncopy = copy;
el.oncut = cut;
} else {
throw new Error('传入的实参格式是否正确?');
}
},
/**
* 判断是安卓端还是ios
* @param {}
* @return {String}
*/
getClientType() {
var userAgent = navigator.userAgent;
var isAndroid = userAgent.indexOf('Android') > -1 || userAgent.indexOf('Adr') > -1; //android终端
var isiOS = !!userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
if (isAndroid) {
return "android";
} else if (isiOS) {
return "ios";
}
return '';
},
/**
* 判断浏览器类型, 并处理逻辑
* @param {Function} callback 回调函数
* ### 未完善 ###
*/
judgeBrowserType: function (callback) {
var Sys = {};
var ua = window.navigator.userAgent.toLowerCase();
var s;
(s = ua.match(/msie ([\d.]+)/)) ? Sys.ie = s[1] :
(s = ua.match(/firefox\/([\d.]+)/)) ? Sys.firefox = s[1] :
(s = ua.match(/chrome\/([\d.]+)/)) ? Sys.chrome = s[1] :
(s = ua.match(/opera.([\d.]+)/)) ? Sys.opera = s[1] :
(s = ua.match(/version\/([\d.]+).*safari/)) ? Sys.safari = s[1] :
(s = ua.match(/MicroMessenger/i)) ? Sys.WeiXin = s[1] : 0;
if (Sys.ie) {
/* 处理 ie 的逻辑 */
callback();
console.log('IE: ' + Sys.ie);
} else if (Sys.firefox) {
/* 处理 firefox 的逻辑 */
callback();
console.log('firefox: ' + Sys.firefox);
} else if (Sys.chrome) {
/* 处理 chrome 的逻辑 */
callback();
console.log('chrome: ' + Sys.chrome);
} else if (Sys.opera) {
/* 处理 opera 的逻辑 */
callback();
console.log('opera: ' + Sys.opera);
} else if (Sys.safari) {
/* 处理 safari 的逻辑 */
callback();
console.log('safari: ' + Sys.safari);
} else if (Sys.WeiXin) {
/* 处理 WeiXin 内置浏览器的逻辑 */
callback();
}
},
}
/* 补充 =========================================================================================== */
/**
* 把一个元素插入到另一个元素后面(无兼容写法)
* @param {Element} targetNode 要插入的元素
* @param {Element} afterNode 指定元素的后面
* 调用:父元素.insertAfter(targetNode, afterNode)
*/
Element.prototype.insertAfter = function (targetNode, afterNode) {
var beforeNode;
// 获取下一个兄弟元素节点
if (afterNode[0]) {
beforeNode = afterNode[0].nextElementSibling
} else {
beforeNode = afterNode.nextElementSibling;
}
if (beforeNode == null || beforeNode == undefined) {
this.appendChild(targetNode);
} else {
this.insertBefore(targetNode, beforeNode);
}
}
/**
* 替换敏感词
* @param {Array} tag
* @param {*} data 数据
*/
// doreplace: function(tag, data) {
// var target = document.getElementsByTagName(tag);
// for (var j = 0; j < target.length; j++) {
// for (var n = 0; n < data.length; n++) {
// if (target[j].innerHTML.indexOf(data[n]['敏感词']) > -1) {
// var str = target[j].innerHTML.replace(eval('/(' + data[n]['敏感词'] + ')/g'), data[n]['替换']);
// target[j].innerHTML = str;
// }
// }
// }
// },
常用函数整理未完,敬请期待…