热搜:fiddler git ip ios 代理
历史搜索

总结一下自己用到的一些工具类

游客2024-10-05 09:30:01
目录文章目录
  1. 数据处理
  2. 金额处理
  3. 事件处理
  4. 文件处理
  5. 正则校验

数据处理

关于浅拷贝和深拷贝更详细的分析请查看:理解 js 的深拷贝和浅拷贝原理和实现的方法

浅拷贝

/**
 * 浅拷贝
 * @param {Object} source
 * @returns {Object}
 */
function clone(source) {
  const result = Object.assign({}, source);
  return result;
}

module.exports = clone;

深拷贝

深拷贝的原理是一层层遍历,直到所有数据都不可继续下探。

/**
 * 深拷贝
 * @param {*} source
 * @param {WeakMap} weakMap
 * @returns {*} target
 */

// 可遍历对象
const iterations = [
  '[object Object]',
  '[object Array]',
  '[object Map]',
  '[object Set]',
];

function cloneDeep(source, weakMap = new WeakMap()) {
  if (source === null) return source;

  // 获取对象类型
  const type = Object.prototype.toString.call(source);

  // 处理不可遍历对象
  if (!iterations.includes(type)) {
    if (type === '[object Date]') return new Date(source);
    if (type === '[object RegExp]') return new RegExp(source);
    if (type === '[object Symbol]') return Symbol(source.description);
    if (type === '[object Function]') return source;
    // 剩余的一般是原始类型,直接返回
    return source;
  }

  // 创建 target 实例
  let target = new source.constructor(); // {} | [] | Map(0) | Set(0)

  // 处理循环调用
  const val = weakMap.get(source);
  if (val) return val;
  weakMap.set(source, target);

  if (type === '[object Map]') {
    source.forEach((value, key) => {
      target.set(key, cloneDeep(value));
    });
    return target;
  }

  if (type === '[object Set]') {
    source.forEach(value => {
      target.add(cloneDeep(value));
    });
    return target;
  }

  // 处理对象和数组
  for (const key in source) {
    target[key] = cloneDeep(source[key], weakMap);
  }
  return target;
}

module.exports = cloneDeep;

任意范围随机数

/**
 * 生成指定范围[min, max]的随机数
 * @param  {Number} min
 * @param  {Number} max
 * @return {Number}
 */
function randomNum(min, max) {
  if (min >= max) return min;

  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

module.exports = randomNum;

数字转百分比

/**
 * 转换百分比
 * @param {number} num
 * @param {number} total
 * @returns {string} 百分比
 */
function toPercent(num, total) {
  let str =
    num >= 0 && total > 0 ? Number(((num / total) * 100).toFixed(2)) : 0;
  return str;
}

module.exports = toPercent;

文件单位自适应

/**
 * 文件大小单位适配,自动转换 B、K、M、G 单位
 * @param {number | string} fileSize 文件大小,以 B 为单位
 * @returns {string}
 */
function translateFileSize(fileSize) {
  if (fileSize === null || typeof fileSize === 'undefined' || fileSize === '') {
    return '—';
  }
  if (fileSize < 1024) {
    fileSize = fileSize + 'B';
  } else if (fileSize < 1024 * 1024) {
    fileSize = Math.floor((fileSize * 10) / 1024) / 10 + 'K';
  } else if (fileSize < 1024 * 1024 * 1024) {
    fileSize = Math.floor((fileSize * 10) / (1024 * 1024)) / 10 + 'M';
  } else {
    fileSize = Math.floor((fileSize * 10) / (1024 * 1024 * 1024)) / 10 + 'G';
  }
  return fileSize;
}

module.exports = translateFileSize;

金额处理

金额超出三位加逗号

/**
 * 金额超出三位加 ','
 * @param {string} num 金额
 * @param {string} locales 本地化配置,默认 zh-CN
 * @param {object} options 本地化配置,默认{ style: 'currency', currency: 'CNY' }
 * @returns {string}
 */
function amountFormat(
  num,
  locales = 'zh-CN',
  options = { style: 'currency', currency: 'CNY' }
) {
  return num ? Number(num).toLocaleString(locales, options) : '0';
}

module.exports = amountFormat;

事件处理

防抖

/**
 * 防抖
 *
 * 用法:
 * const cbFun = debounce(fun, 2000)
 * cbFun()
 */
function debounce(fn, delay = 1000) {
  let timer = null;
  return function() {
    if (timer !== null) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      fn.apply(this, arguments);
    }, delay);
  };
}

module.exports = debounce;

节流

/**
 * 节流
 *
 * 用法:
 * const cbFun = throttle(fun, 2000)
 * cbFun()
 */
function throttle(fn, delay = 1000) {
  let old = 0;
  return function() {
    let now = new Date().valueOf();
    if (now - old > delay) {
      fn.apply(this, arguments);
      old = now;
    }
  };
}

module.exports = throttle;

定时器

var requestAnimFrame = (function() {
  return (
    window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    function(callback) {
      window.setTimeout(callback, 1000 / 60);
    }
  );
})();

/**
 * rAF 定时器
 *
 * 用法:
 * const cbFun = rafInterval(fun, 2000)
 * cbFun()
 */
function rafInterval(fn, delay = 1000) {
  let start = 0;
  function fun() {
    const timestamp = new Date().valueOf();
    if (start === undefined) start = timestamp;
    if (timestamp - start > delay) {
      start = timestamp;
      fn.apply(this, arguments);
    }
    requestAnimFrame(fun);
  }
  return function() {
    requestAnimFrame(fun);
  };
}

module.exports = rafInterval;

文件处理

导出文件

/**
 * 导出文件
 * @param {string} biteData 字节流
 * @param {string} title 文件名
 * @param {string} ext 文件后缀
 */
function downloadFile(biteData, title = '导出', ext = 'xls') {
  let blob = new Blob([biteData], { type: 'application/octet-binary' });
  let downloadElement = document.createElement('a');
  let href = window.URL.createObjectURL(blob);
  downloadElement.target = '_blank';
  downloadElement.href = href;
  downloadElement.download = `${title}.${ext}`; // 文件名
  document.body.appendChild(downloadElement);
  downloadElement.click();
  document.body.removeChild(downloadElement);
  window.URL.revokeObjectURL(href); // 释放掉 blob 对象
}

module.exports = downloadFile;

json 导出 csv 文件

/**
 * JSON 数据转成 CSV 文件导出
 * @param {Array} list 要导出的 JSON 数据
 * @param {Array} cols 表头名称,格式如:['ID', '姓名', '性别'],默认用第一条数据的 key
 * @param {Array} keys 表头使用的 key,格式如:['id', 'name', 'gender'],需要和 cols 一一对应,否则导出数据有问题,默认用第一条数据的 key
 * @param {string} fileName 导出的文件名称,不含日期前缀和文件类型后缀的部分
 *
 * 用法:
 * json2Csv(list, cols, keys, fileName)
 */

function json2Csv(list, cols, keys, fileName = '数据明细') {
  if (
    !(
      list instanceof Array &&
      cols instanceof Array &&
      keys instanceof Array &&
      typeof fileName === 'string'
    )
  ) {
    console.log('参数格式错误');
    return;
  }
  if (list.length === 0) return;

  if (cols.length === 0) cols = Object.keys(list[0]);
  if (keys.length === 0) keys = Object.keys(list[0]);
  fileName = fileName || '数据明细';

  let title = cols;
  let jsonKey = keys;
  let data = list;
  let str = [];
  str.push(title.join(',') + 'n');
  for (let i = 0; i < data.length; i++) {
    let temp = [];
    for (let j = 0; j < jsonKey.length; j++) {
      temp.push(data[i][jsonKey[j]]);
    }
    str.push(temp.join(',') + 'n');
  }
  let uri =
    'data:text/csv;charset=utf-8,ufeff' + encodeURIComponent(str.join(''));
  let downloadLink = document.createElement('a');
  downloadLink.href = uri;
  downloadLink.download =
    new Date().toISOString().substring(0, 10) + '-' + fileName + '.csv';
  document.body.appendChild(downloadLink);
  downloadLink.click();
  document.body.removeChild(downloadLink);
}

module.exports = json2Csv;

正则校验

邮箱

/**
 * 判断邮箱格式
 * @param {string} str
 * @returns {Boolean}
 */

function isEmailNum(str, type = 1) {
  return /^[A-Za-z0-9_u4e00-u9fa5]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$/.test(
    str
  );
}

module.exports = isEmailNum;

身份证

/**
 * 判断是否为身份证号
 * @param  {string | number} str
 * @returns {Boolean}
 */
function isIdCard(str) {
  return /^(^[1-9]d{7}((0d)|(1[0-2]))(([0|1|2]d)|3[0-1])d{3}$)|(^[1-9]d{5}[1-9]d{3}((0d)|(1[0-2]))(([0|1|2]d)|3[0-1])((d{4})|d{3}[Xx])$)$/.test(
    str
  );
}

module.exports = isIdCard;

手机号码

/**
 * 判断是否为电话号码,会过滤掉空格和横杠
 * @param {string | number} str 手机号码
 * @returns {Boolean}
 */

function isPhoneNum(str, type = 1) {
  str = str
    .replace(/ /g, '')
    .replace(/-/g, '')
    .replace(/(|)|(|)/g, ''); // 去除空格、横杠和括号
  return /^(+?0?86-?)?1[3456789]d{9}$/.test(str);
}

module.exports = isPhoneNum;

座机号码

/**
 * 判断是否为电话号码,会过滤掉空格和横杠
 * @param {string | number} str 电话号码
 * @returns {Boolean}
 */

function isPhoneNum(str, type = 1) {
  str = str
    .replace(/ /g, '')
    .replace(/-/g, '')
    .replace(/(|)|(|)/g, ''); // 去除空格、横杠和括号
  return /^(d{3,4})?[0-9]{7,8}$/.test(str);
}

module.exports = isPhoneNum;

以上仅仅是根据自己业务需求整理的,不一定适用所有项目,如有问题,欢迎指正~

标签:前端