最近居家,回顾问题解解闷。明天汇总一下过来一年用的工具类(github开源仓库,请骁勇star),顺便发个npm包:haUtil

数据处理

对于浅拷贝和深拷贝更具体的剖析请查看:清晰易懂!解说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][email protected][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}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(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;

以上仅仅是依据本人业务需要整顿的,不肯定实用所有我的项目,如有问题,欢送斧正~