1. 简单数组去重
- 第一种方式:
使用 reduce 函数返回值是累加的结果,判断当前遍历值是否在其中。
function removeDuplicates(arr) {
let result = arr.reduce(function (init, current) {
if (init.indexOf(current) === -1) {
init.push(current);
}
return init;
}, []);
return result;
}
let myArray = ["a", "b", "a", "b", "c", "e", "e", "c", "d", "d", "d", "d"];
console.log(removeDuplicates(myArray)); // ["a", "b", "c", "e", "d"]
- 第二种方式:
先使用排序,把相同的元素放到一起,然后再使用 reduce 方法让当前遍历对象跟前一个进行比较,相同就不加入,不同则加入。
function removeDuplicates(arr) {
let result = arr.sort().reduce((init, current) => {
if (init.length === 0 || init[init.length - 1] !== current) {
init.push(current);
}
return init;
}, []);
return result;
}
let arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
console.log(removeDuplicates(arr)); //[1,2,3,4,5]
- 第三种方式:
利用 indexOf 总是返回该项的第一个出现的索引,所以我们可以判断当前在过滤循环中的项是否是重复的。如果是,我们就不返回到由 filter()方法创建的新数组中。
function removeDuplicates(arr) {
let result = arr.filter((item, index) => {
return arr.indexOf(item) === index;
});
return result;
}
let arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
console.log(removeDuplicates(arr)); //[1,2,3,4,5]
2. 数组中对象去重
function removeDuplicates(arr) {
const tempObj = {};
let result = arr.reduce((init, current) => {
tempObj[current.name]
? ""
: (tempObj[current.name] = true && init.push(current));
return init;
}, []);
return result;
}
// 注意: name字段必须为current中存在的字段
3. 扁平化嵌套数组
- 方式一:
使用 flat 方法,该方法接受一个可选参数,几维数组展开就把数字几作为参数,使用 Infinity 作为参数时可展开任意深度的嵌套数组
function flatArray(arr) {
return arr.flat();
}
- 方法二:
使用 reduce 方法,该方法仅适用于二维数组
function flatArray(arr) {
return arr.reduce((init, current) => init.concat(current), []);
}
4. 将数组转化为树形结构
- 将如下数据转化为树状结构
let arr = [
{
id: 1,
name: "1",
pid: 0,
},
{
id: 2,
name: "1-1",
pid: 1,
},
{
id: 3,
name: "1-1-1",
pid: 2,
},
];
- 实现方式
function toTree(data, parentId = 0) {
var itemArr = [];
for (var i = 0; i < data.length; i++) {
var node = data[i];
if (node.pid === parentId) {
var newNode = {
...node,
name: node.name,
id: node.id,
children: toTree(data, node.id),
};
itemArr.push(newNode);
}
}
return itemArr;
}
5. 格式化时间
- 方式一:
const getDate = (timeStamp, format, type) => {
const d = new Date(timeStamp || 0);
const year = d.getFullYear();
const month = getHandledValue(d.getMonth() + 1);
const day = getHandledValue(d.getDate());
const hour = getHandledValue(d.getHours());
const minute = getHandledValue(d.getMinutes());
const second = getHandledValue(d.getSeconds());
let resStr = "";
if (!type) {
type = "/";
}
switch (format) {
case "yyyymmdd":
return [year, month, day].map(formatNumber).join(type);
case "yyyymm":
return [year, month].map(formatNumber).join(type);
case "mmdd":
return [month, day].map(formatNumber).join(type);
case "yyyy":
return year;
case "mm":
return [month].map(formatNumber);
case "dd":
return [day].map(formatNumber);
case "yyyymmddhhmmss":
return (
[year, month, day].map(formatNumber).join(type) +
" " +
[hour, minute, second].map(formatNumber).join(":")
);
case "yyyymmddhhmm":
return (
[year, month, day].map(formatNumber).join(type) +
" " +
[hour, minute].map(formatNumber).join(":")
);
case "hhmmss":
return [hour, minute, second].map(formatNumber).join(":");
case "hhmm":
return [hour, minute].map(formatNumber).join(":");
case "hh":
return [hour].map(formatNumber);
case "mi":
return [minute].map(formatNumber);
default:
return (
[year, month, day].map(formatNumber).join("/") +
" " +
[hour, minute, second].map(formatNumber).join(":")
);
}
};
- 方式二:
const formatTime = (date) => {
let fmt = 'yyyy-MM-dd hh:mm:ss'
const o = {
'M+': date.getMonth() + 1, // 月份
'd+': date.getDate(), // 日
'h+': date.getHours(), // 小时
'm+': date.getMinutes(), // 分钟
's+': date.getSeconds(), // 秒
}
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, date.getFullYear())
}
for (let k in o) {
if (new RegExp('(' + k + ')').test(fmt)) {
fmt = fmt.replace(RegExp.$1, o[k].toString().length == 1 ? '0' + o[k] : o[k])
}
}
return fmt
}
6. 获取相对时间
/**
* @param {String|Number} timeStamp 时间戳
* @returns {String} 相对时间字符串
*/
const getRelativeTime = (timeStamp) => {
// 判断当前传入的时间戳是秒格式还是毫秒
const IS_MILLISECOND = isMillisecond(timeStamp);
// 如果是毫秒格式则转为秒格式
if (IS_MILLISECOND) Math.floor((timeStamp /= 1000));
// 传入的时间戳可以是数值或字符串类型,这里统一转为数值类型
timeStamp = Number(timeStamp);
// 获取当前时间时间戳
const currentTime = Math.floor(Date.parse(new Date()) / 1000);
// 判断传入时间戳是否早于当前时间戳
const IS_EARLY = isEarly(timeStamp, currentTime);
// 获取两个时间戳差值
let diff = currentTime - timeStamp;
// 如果IS_EARLY为false则差值取反
if (!IS_EARLY) diff = -diff;
let resStr = "";
const dirStr = IS_EARLY ? "前" : "后";
// 少于等于59秒
if (diff <= 59) resStr = diff + "秒" + dirStr;
// 多于59秒,少于等于59分钟59秒
else if (diff > 59 && diff <= 3599)
resStr = Math.floor(diff / 60) + "分钟" + dirStr;
// 多于59分钟59秒,少于等于23小时59分钟59秒
else if (diff > 3599 && diff <= 86399)
resStr = Math.floor(diff / 3600) + "小时" + dirStr;
// 多于23小时59分钟59秒,少于等于29天59分钟59秒
else if (diff > 86399 && diff <= 2623859)
resStr = Math.floor(diff / 86400) + "天" + dirStr;
// 多于29天59分钟59秒,少于364天23小时59分钟59秒,且传入的时间戳早于当前
else if (diff > 2623859 && diff <= 31567859 && IS_EARLY)
resStr = getDate(timeStamp);
else resStr = getDate(timeStamp, "year");
return resStr;
};
7. 获取当前浏览器
/**
* @returns {String} 当前浏览器名称
*/
const getExplorer = () => {
const ua = window.navigator.userAgent;
const isExplorer = (exp) => {
return ua.indexOf(exp) > -1;
};
if (isExplorer("MSIE")) return "IE";
else if (isExplorer("Firefox")) return "Firefox";
else if (isExplorer("Chrome")) return "Chrome";
else if (isExplorer("Opera")) return "Opera";
else if (isExplorer("Safari")) return "Safari";
};
8. 判断两个对象是否相等
/**
* @param {*} obj1 对象
* @param {*} obj2 对象
* @description 判断两个对象是否相等,这两个对象的值只能是数字或字符串
*/
const objEqual = (obj1, obj2) => {
const keysArr1 = Object.keys(obj1);
const keysArr2 = Object.keys(obj2);
if (keysArr1.length !== keysArr2.length) return false;
else if (keysArr1.length === 0 && keysArr2.length === 0) return true;
/* eslint-disable-next-line */ else
return !keysArr1.some((key) => obj1[key] != obj2[key]);
};
9. 百分比转小数
const percentageToDecimal = (num) => {
if (typeof num !== "number") num = Number(num);
let convert = num;
let unit = 100;
return convert / unit;
};
10. 小数转百分比
const decimalToPercentage = (num) => {
if (num && typeof num === "number") {
let convert = num;
let unit = 100;
return convert * unit;
} else {
return num;
}
};
11. 数组按指定份数分割
const splitArr = (data, senArrLen) => {
//处理成len个一组的数据
let data_len = data.length;
let arrOuter_len =
data_len % senArrLen === 0
? data_len / senArrLen
: parseInt(data_len / senArrLen + "") + 1;
let arrSec_len = data_len > senArrLen ? senArrLen : data_len; //内层数组的长度
let arrOuter = new Array(arrOuter_len); //最外层数组
let arrOuter_index = 0; //外层数组的子元素下标
for (let i = 0; i < data_len; i++) {
if (i % senArrLen === 0) {
arrOuter_index++;
let len = arrSec_len * arrOuter_index;
//将内层数组的长度最小取决于数据长度对len取余,平时最内层由下面赋值决定
arrOuter[arrOuter_index - 1] = new Array(data_len % senArrLen);
if (arrOuter_index === arrOuter_len)
//最后一组
data_len % senArrLen === 0
? (len = (data_len % senArrLen) + senArrLen * arrOuter_index)
: (len = (data_len % senArrLen) + senArrLen * (arrOuter_index - 1));
let arrSec_index = 0; //第二层数组的索引
for (let k = i; k < len; k++) {
//第一层数组的开始取决于第二层数组长度*当前第一层的索引
arrOuter[arrOuter_index - 1][arrSec_index] = data[k];
arrSec_index++;
}
}
}
return arrOuter;
};
12. 下载图片
const downloadImg = (imgsrc, name) => {
//下载图片地址和图片名
let image = new Image();
// 解决跨域 Canvas 污染问题
image.setAttribute("crossOrigin", "anonymous");
image.onload = function () {
let canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
let context = canvas.getContext("2d");
context.drawImage(image, 0, 0, image.width, image.height);
let url = canvas.toDataURL("image/png"); //得到图片的base64编码数据
let a = document.createElement("a"); // 生成一个a元素
let event = new MouseEvent("click"); // 创建一个单击事件
a.download = name || "photo"; // 设置图片名称
a.href = url; // 将生成的URL设置为a.href属性
a.dispatchEvent(event); // 触发a的单击事件
};
image.src = imgsrc;
};
13. 拖拽移动
export const dragToMove = (dragDom, dragId) => {
var startEvt, moveEvt, endEvt;
// 判断是否支持触摸事件
if ("ontouchstart" in window) {
startEvt = "touchstart";
moveEvt = "touchmove";
endEvt = "touchend";
} else {
startEvt = "mousedown";
moveEvt = "mousemove";
endEvt = "mouseup";
}
// 获取元素
var drag = dragDom;
var disX, disY, left, top, starX, starY;
var firstTime = "",
lastTime = "";
drag.addEventListener(startEvt, function (e) {
// 阻止页面的滚动,缩放
e.preventDefault();
document.getElementById(dragId).setAttribute("data-flag", false);
firstTime = new Date().getTime();
// 兼容IE浏览器
var e = e || window.event;
// 手指按下时的坐标
starX = e.touches ? e.touches[0].clientX : e.clientX;
starY = e.touches ? e.touches[0].clientY : e.clientY;
// 手指相对于拖动元素左上角的位置
disX = starX - drag.offsetLeft;
disY = starY - drag.offsetTop;
document.addEventListener(moveEvt, moveFun);
document.addEventListener(endEvt, endFun);
});
function moveFun(e) {
// 兼容IE浏览器
var e = e || window.event;
left = (e.touches ? e.touches[0].clientX : e.clientX) - disX;
top = (e.touches ? e.touches[0].clientY : e.clientY) - disY;
// 限制拖拽的X范围,不能拖出屏幕
if (left < 0) {
left = 0;
} else if (left > document.documentElement.clientWidth - drag.offsetWidth) {
left = document.documentElement.clientWidth - drag.offsetWidth;
}
// 限制拖拽的Y范围,不能拖出屏幕
if (top < 0) {
top = 0;
} else if (
top >
document.documentElement.clientHeight - drag.offsetHeight
) {
top = document.documentElement.clientHeight - drag.offsetHeight;
}
drag.style.left = left + "px";
drag.style.top = top + "px";
}
function endFun(e) {
document.removeEventListener(moveEvt, moveFun);
document.removeEventListener(endEvt, endFun);
lastTime = new Date().getTime();
if (lastTime - firstTime < 200) {
document.getElementById(dragId).setAttribute("data-flag", true);
if (endEvt == "touchend") {
document.getElementById(dragId).click();
}
}
}
};
14. 从 url 中解析出参数
/**
* @param {String} url
* @description 从URL中解析参数
*/
const getParams = (url) => {
const keyValueArr = url.split("?")[1].split("&");
let paramObj = {};
keyValueArr.forEach((item) => {
const keyValue = item.split("=");
paramObj[keyValue[0]] = keyValue[1];
});
return paramObj;
};
15. 格式化金额
const formatNumber = (val = 0) => {
isNaN(val) ? (val = 0) : val;
return (val * 1).toLocaleString("zh", { minimumFractionDigits: 2 });
};
16. 加减乘法
// 减法#
const subtr = (arg1, arg2) => {
let num1 = arg1 || 0;
let num2 = arg2 || 0;
let r1, r2, m, n;
try {
r1 = num1.toString().split(".")[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = num2.toString().split(".")[1].length;
} catch (e) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));
n = r1 >= r2 ? r1 : r2;
return ((mul(num1, m) - mul(num2, m)) / m).toFixed(n);
};
//乘法
const mul = (arg1, arg2) => {
let m = 0,
s1 = arg1.toString(),
s2 = arg2.toString();
try {
m += s1.split(".")[1].length;
} catch (e) {}
try {
m += s2.split(".")[1].length;
} catch (e) {}
return (
(Number(s1.replace(".", "")) * Number(s2.replace(".", ""))) /
Math.pow(10, m)
);
};
//加法
const accAdd = (arg1, arg2) => {
let num1 = arg1 || 0;
let num2 = arg2 || 0;
let r1, r2, m;
try {
r1 = num1.toString().split(".")[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = num2.toString().split(".")[1].length;
} catch (e) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));
return (mul(num1, m) + mul(num2, m)) / m;
};
17. 自定义指令-按钮权限控制
Vue.directive("has", {
inserted: function (el, binding) {
if (!Vue.prototype.$has(binding.value)) {
el.parentNode.removeChild(el);
}
},
});
18. 自定义指令-防快速重复点击按钮
import Vue from "vue";
Vue.directive("preventReClick", {
inserted(el) {
el.addEventListener("click", () => {
if (!el.disabled) {
el.disabled = true;
setTimeout(() => {
el.disabled = false;
}, 2000);
}
});
},
});
19. 获取时间差
const getDateDiff = (startTime, endTime, diffType) => {
// 将xxxx-xx-xx的时间格式,转换为 xxxx/xx/xx的格式
startTime = startTime.replace(/-/g, "/");
endTime = endTime.replace(/-/g, "/");
// 将计算间隔类性字符转换为小写
diffType = diffType.toLowerCase();
var sTime = new Date(startTime); // 开始时间
var eTime = new Date(endTime); // 结束时间
// 作为除数的数字
var divNum = 1;
switch (diffType) {
case "second":
divNum = 1000;
break;
case "minute":
divNum = 1000 * 60;
break;
case "hour":
divNum = 1000 * 3600;
break;
case "day":
divNum = 1000 * 3600 * 24;
break;
default:
break;
}
return parseInt((eTime.getTime() - sTime.getTime()) / parseInt(divNum));
};
20. 获取文件扩展名
const getFileType = (filePath) => {
var startIndex = filePath.lastIndexOf(".");
if (startIndex !== -1) {
return filePath.substring(startIndex + 1, filePath.length).toLowerCase();
} else {
return "";
}
};
21. 判断数组中是否有重复对象
const isRepeat = (arr) => {
const obj = {};
let flag = false;
arr.map((item) => {
obj[item.id] ? (flag = true) : (obj[item.id] = true);
});
return flag;
};
22. 压缩图片
export function compress(fileObj) {
return new Promise(resolve => {
function dataURLtoBlob(dataUrl) {
//base64格式图片 转为Blob
const arr = dataUrl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1])
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], fileObj.name, {
lastModified: fileObj.lastModifiedDate,
type: mime
})
}
if (typeof FileReader === 'undefined') {
console.log('当前浏览器内核不支持base64图标压缩')
resolve(fileObj)
}
try {
const reader = new FileReader()
const image = new Image()
reader.readAsDataURL(fileObj) //开始读取指定的Blob中的内容。返回base64
reader.onload = function (ev) {
image.src = String(ev.target.result)
image.onload = function () {
let imgWidth = image.width,
imgHeight = image.height //获取图片宽高
//设置图片的最大宽度为300
imgWidth = image.width
imgHeight = image.height //设置等比例高度
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = imgWidth
canvas.height = imgHeight
ctx.drawImage(image, 0, 0, imgWidth, imgHeight) //根据宽高绘制图片
const fullQuality = canvas.toDataURL('image/jpeg', 0.05) //canvas转为base64
const blogData = dataURLtoBlob(fullQuality)
resolve(blogData)
}
}
} catch (e) {
resolve(fileObj)
}
})
}
23. 大数字转换为万/亿
/*
* @params : num 数字
* @params : point 保留几位小数
*/
export function transferNumber(num, point) {
let numStr = num.toString().split('.')[0]
if (numStr.length < 6) { // 十万以下不转化原数字显示
return numStr
} else if (numStr.length >= 6 && numStr.length <= 8) {
// 6-8位:十万 - 千万 转化为万
let decimal = numStr.substring(numStr.length - 4, numStr.length - 4 + point)
return parseFloat(parseInt(num / 10000) + '.' + decimal) +
'万'
} else if (numStr.length > 8) {
// 超过8为 显示亿
let decimal = numStr.substring(numStr.length - 8, numStr.length - 8 + point)
return parseFloat(parseInt(num / 100000000) + '.' + decimal) + '亿'
}
}