比对对象差异值,返回新对象的差异值
/**
* 比对新对象和旧对象的差异值,返回新对象的差异值
* @param { object } newObj 新对象
* @param { object } oldObj 旧对象
* @return { object } obj 新对象的差异值
*/
export const Difference = (newObj,oldObj) => {
let diff = {};
for(let k in newObj){
if(newObj[k] != oldObj[k]){
diff[k] = newObj[k]
}
}
return diff;
}
获取省市区树形结构的所有code
// 示例数据
let area = [{
"code": "420000",
"name": "湖北省",
"icon" : 'icon',
"children": [{
"code": "420100",
"name": "武汉市",
"children": [{
"code": "420101",
"name": "市辖区"
}, {
"code": "420102",
"name": "江岸区"
}, {
"code": "420103",
"name": "江汉区"
}, ]
}]
},
// 其它省......
]
/**
* 获取树形数据的所有节点code
* @param {array} area 树形数据
* @return {array} 所有节点的code
*/
export const getTreeCode = (area) => {
let allCode = []
shell(area)
function shell(area) {
area.forEach((item) => {
bicycle(item)
})
function bicycle(area) {
allCode.push(area.code)
if (area?.children?.length > 0) {
shell(area.children)
}
}
}
return allCode
}
递归适用于深层数据查找,这种查找是单行的,如果要获取所有节点数据则需要遍历递归,拿到所有分支的数据。
判断code在树形数据中是否存在
/**
* 判断code在树形数据中是否存在
* @param {array} area 树形数据
* @param {string} code 需要判断的code
* @return {boolean} true\false
*/
export const treeCodeExist = (area, code) => {
let exist = false;
shell(area)
function shell(area) {
area.forEach((item) => {
bicycle(item)
})
function bicycle(area) {
if(code == area.code){
return exist = true
}
if (area?.children?.length > 0) {
shell(area.children)
}
}
}
return exist
}
判断开始时间和结束时间是否大于12个月
/**
* 判断开始时间和结束时间是否大于12个月
* @param {string} startTime 开始时间,如:'2023-09-14'
* @param {string} endTime 结束时间,如:'2023-12-10'
* @return {boolean} true\false
*/
const dateLimit = (startTime,endTime) => {
let start = startTime.split('-');
let end = endTime.split('-');
let y = end[0] - start[0];
let m = 0;
if(y > 0){
let allMonth = y * 12;
m = allMonth - Number(start[1]) + Number(end[1]);
} else {
m = end[1] - start[1];
}
if(m === 12){
if(end[2] > start[2])
{ return true } else
{ return false }
}
if(m > 12)
{ return true } else
{ return false }
}
删除数组中多个指定元素
a = [1,3,4,2,5] / b = [2,3]
预期结果:[1,4,5]
这里要用到倒叙删除,因为数组的length是动态的,在循环中正序删除会导致下标不准。
/***
* @param {array} arr 原数组
* @param {array} ids 需要删除的id数组
* @return {array} 删除的数组
*/
const arrMoreDeletion = (arr,ids) => {
for(let i = arr.length -1 ; i >= 0 ; i--){
for(let j = 0; j < ids.length ; j++){
// 如果是数组对象这里就改为arr[i].id
if(arr[i] == ids[j]){
arr.splice(i,1)
}
}
}
return arr;
}
有条件数组交叉合并
let list = [
{id:1,name:'花园评分',value:''},
{id:2,name:'小区评分',value:''},
{id:3,name:'街道评分',value:''},
{id:4,name:'小区描述',value:''},
{id:6,name:'花园描述',value:''},
{id:7,name:'公园评分',value:''},
{id:8,name:'街道描述',value:''},
{id:9,name:'公园描述',value:''}
]
let arr = list.filter(el => el.name.includes('评分'))
let arr2 = list.filter(el => el.name.includes('描述'))
let info = []; // 最终结果
arr.forEach(el => {
info.push(el);
let text = el.name.replace('评分','');
for(let i = 0; i < arr2.length ; i++){
if(arr2[i].name.includes(text)){
info.push(arr2[i]);
break;
}
}
})
无条件数组交叉合并
以A组为基础插入B组数据,如果A组数据少于B组,那么B组多出来的数据依次向下排列。
let listA = [
{ name: 'A组01' },
{ name: 'A组02' },
{ name: 'A组03' }
]
let listB = [
{ name: 'B组01' },
{ name: 'B组02' },
{ name: 'B组03' }
]
/***
* @param {array} listA 数组A
* @param {array} listB 数组B
* @return {array} 数组A\B的交叉数组
*/
const crossList = (listA = [] , listB = []) => {
let info = []; // 最终结果
let a = listA.length;
let b = listB.length;
let state = a >= b; // 比较A组是否 >= B组
listA.forEach((el, index) => {
info.push(el); // 添加A组每一项
if (index + 1 <= b) {
info.push(listB[index]); // 在A组遍历中,同时添加B组数据
}
});
// B组大于A组,将B组的数据在数组末尾依次排列
if (!state) {
let diff = b - a;
let arr = []
for (let i = 0; i < diff; i++) {
arr.push(listB.reverse()[i]); // 反转,从尾部向前添加
}
info.push(...arr.reverse()); // 二次反转,改为正常顺序添加
}
return info;
}
crossList(listA , listB);
生成随机字符串
/***
* @param {number} num 需要生成多少位随机字符
* @return {string} 生成的随机字符
*/
export const randomString = (num) => {
let str = "",
arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
let index = null;
for (let i = 0; i < num; i++) {
index = Math.round(Math.random() * (arr.length - 1));
str += arr[index];
}
return str;
}
过滤所有节点树中的子节点
所有的子节点和父节点在一维数组中,过滤出所有节点的子项,这里的子项也就是children的最后一层
场景:后端返回所有勾选和半勾选节点,比如返回杭州市并且返回杭州市下的某几个区,我们要拿这样的数据回显树勾选节点,如果直接回显,由于返回了杭州市,杭州市下的所有区会全部勾选,所以需要过滤子节点,通过子节点反向勾选父节点,如果子节点其中某几个节点勾选,父节点半选,如果子节点全部勾选,父节点就会自动勾选。
原理:根据返回的fiLevel层级分组,例如:1、2、3组(省、市、区)然后遍历所有层级,通过fvParentId比对是否有children,最后过滤出没有children的节点。
let treeAll = [
{
"id":3425,
"fiAreaCode":"330000",
"fiDeptId":null,
"fiLevel":1,
"fvParentId":"0",
"fiAffiliation":0,
"fvAreaName":"浙江省",
"fvEstateType":null
},
{
"id":3426,
"fiAreaCode":"330100",
"fiDeptId":null,
"fiLevel":2,
"fvParentId":"330000",
"fiAffiliation":0,
"fvAreaName":"杭州市",
"fvEstateType":null
},
{
"id":3457,
"fiAreaCode":"310005",
"fiDeptId":null,
"fiLevel":3,
"fvParentId":"330100",
"fiAffiliation":0,
"fvAreaName":"临平区",
"fvEstateType":null
},
{
"id":3458,
"fiAreaCode":"310009",
"fiDeptId":null,
"fiLevel":3,
"fvParentId":"330100",
"fiAffiliation":0,
"fvAreaName":"上城区",
"fvEstateType":null
},
{
"id":3425,
"fiAreaCode":"33001200",
"fiDeptId":null,
"fiLevel":1,
"fvParentId":"0",
"fiAffiliation":0,
"fvAreaName":"我的省",
"fvEstateType":null
},
{
"id":3425,
"fiAreaCode":"3300123400",
"fiDeptId":null,
"fiLevel":1,
"fvParentId":"0",
"fiAffiliation":0,
"fvAreaName":"我的省2",
"fvEstateType":null
},
]
function shiftArea(treeAll) {
let treeObj = {};
// 层级分组
treeAll.forEach(item => {
let level = item.fiLevel;
if(!treeObj[level]){
treeObj[level] = [];
}
treeObj[level].push(item);
})
let all = []; // 保存所有节点
// 遍历所有节点
Object.values(treeObj).forEach(item => {
// 对节点深层遍历
item.forEach(item2 => {
item2.chindren = []; // 子级默认为空数组
// 设置children子级节点
treeAll.forEach(item3 => {
if(item2.fiAreaCode == item3.fvParentId){
item2.chindren.push(item3)
}
})
all.push(item2)
})
})
// 过滤出所有子级节点
let outcome = all.filter(item => item.chindren.length == 0)
return outcome
}
shiftArea(treeAll)
获取数值在数组中的近似值
/***
* @param {array} arr 数组,如:[23, 30, 35, 47, 16, 21]
* @param {number} num 当前值,如37
* @return {string} 当前值在数组中最接近的值
*/
const closest = (arr, num) => {
var ret = arr[0];
var distance = Math.abs(ret - num);
for(var i = 1; i < arr.length; i++){
var newDistance = Math.abs(arr[i] - num);
if(newDistance < distance){
distance = newDistance;
ret = arr[i];
}
}
return ret;
}
let arr = [23, 30, 35, 47, 16, 21]
let num = 37
console.log(closest(arr,num)); // 35
根据上限值计算涨幅和减幅
/**
* 根据当前值和上限值计算涨幅和减幅,例如:
* 上限100,当前45,那么45 = 100涨幅122.22222222222223%
* 上限100,当前145,145 = 100,减幅31.03448275862069%
* @param {Object} a 当前值
* @param {Object} max 上限值
* @returns {Object || Boolean} false表示无任何涨幅或不符合规则,Object.type:1涨幅 2减幅
*/
getPercent(a,max) {
// 无涨幅或不符合规则
if(a == 0 || !a) return false
if (a < max) {
// 涨幅
// 即 max 相对于 a 增加了百分之多少
const increase = ((max - a) / a) * 100;
return {
percent: increase,
type: 1, // 涨幅
}
} else if (a > max) {
// 减幅
// 即 a 相对于 max 减少了百分之多少
const decrease = ((a - max) / a) * 100;
return {
percent: decrease,
type: 2, // 减幅
}
} else {
// 没有任何涨幅,与max对等
return false
}
}
根据涨幅和减幅计算实际值
/**
* 根据涨幅和减幅计算实际值,调用上面的计算涨幅函数
* @param {Number} num 要计算的值
* @param {Object} extent
* @returns {Number} 计算后的值,保留两位小数
*/
getValue(num,extent) {
if(!extent) return num
if(extent.type == 1){
let n = num * (1 + (extent.percent / 100)); // 根据涨幅公式计算最终值
return parseInt(n * 100) / 100
} else {
let n = item.value * (1 - (extent.percent / 100)); // 根据涨幅公式计算最终值
return parseInt(n * 100) / 100
}
}
秒转时分秒
/**
* 根据涨幅和减幅计算实际值,调用上面的计算涨幅函数
* @param {Number} num 要计算的值
* @param {Object} extent
* @returns {Number} 计算后的值,保留两位小数
*/
const formatTime = (seconds) => {
let hours = Math.floor(seconds / 3600);
let minutes = Math.floor((seconds - (hours * 3600)) / 60);
let remainingSeconds = seconds - (hours * 3600) - (minutes * 60);
// 添加前导零
hours = String(hours).padStart(2, '0');
minutes = String(minutes).padStart(2, '0');
remainingSeconds = String(remainingSeconds).padStart(2, '0');
return `${hours}小时${minutes}分${remainingSeconds}秒`
}
console.log(formatTime(661)); // 输出: 00小时11分01秒
console.log(formatTime(7200)); // 输出: 02小时00分00秒
过滤出前后指定N年符合区间的时间
/**
* 从当前时间开始,过滤出前后指定N年符合区间的时间
* @param {string} time 当前时间
* @param {monthStar} 指定月份第一天
* @param {monthEnd} 指定月份最后一天
* @param {diff} 前后多少年
* @returns {Boolean} 是否符合:treu / false
*/
const getTimeFrame = (time,monthStar,monthEnd,diff) => {
const getTimestamp = (str) => new Date(str.substring(0, 19).replace(/-/g, '/')).getTime();
let date = new Date();
let year = date.getFullYear();
let star = year - diff;
let end = year + diff
let arr = [];
for(let i = 0 ; i < end - star ; i ++){
arr.push({star:`${star+i}-${monthStar}`,end:`${star+i}-${monthEnd}`})
}
let state = arr.some(el => {
return getTimestamp(time) >= getTimestamp(el.star) && getTimestamp(time) <= getTimestamp(el.end)
})
return state
}
// 从当前时间开始,过滤出前后10年符合区间的时间
getTimeFrame('2024-12-01','12-01','12-31',10); // true
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。