头图

比对对象差异值,返回新对象的差异值

/**
 * 比对新对象和旧对象的差异值,返回新对象的差异值
 * @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
}

递归适用于深层数据查找,这种查找是单行的,如果要获取所有节点数据则需要遍历递归,拿到所有分支的数据。
image.png

判断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;
     }
  }
})

image.png

无条件数组交叉合并

以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);

image.png

生成随机字符串

/***
 * @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)

image.png

获取数值在数组中的近似值

/***
 * @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

兔子先森
466 声望555 粉丝

致力于新技术的推广与优秀技术的普及。