前端常用工具库方法整理

2023-11-16

欢迎点击领取 -《前端面试题进阶指南》:前端登顶之巅-最全面的前端知识点梳理总结

前言

在闲余的时间整理一份我们可能用到的前端工具库方法。

依赖库 名称
cropperjs 图片裁剪
exif-js、lrz 图片旋转问题
html2canvas dom转图片
nprogress 路由进度条
v-viewer 图片放大多功能
caret-pos 偏移量
1.获取url地址参数
export function getQueryStringByStr(data) {
	const url = data; // 获取url中"?"符后的字串
	const theRequest = {};
	if (url.indexOf('?') !== -1) {
		const str = url.substr(1);
		const strs = str.split('&');
		for (let i = 0; i < strs.length; i += 1) {
		theRequest[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1]);
		}
	}
	return theRequest;
}
2.针对检索值(搜索)统一处理空格问题
/**
 * @param {Object} props
 * @description 针对搜索值做统一处理
 */
export function convertParams(props) {
  const newParams = {};
  for (const index in props) {
    const item = props[index];
    const type = typeof item;
    if (item && type === 'string') {
       newParams[index] = item.replace(/\s/g, '');
     } if (Object.prototype.toString.call(item) === '[object Object]') {
        newParams[index] = convertParams(item)
      } else {
       newParams[index] = item;
     }
  }
  return newParams;
};
3.权限方法判断
/**
 * @param {Array|String} target 目标数组
 * @param {Boolean} boolean 是否开启与的关系
 * @description 判断当前用户是否在权限数据中
 */
export const authority = (target, boolean = false) => {
  const str = getProps('authority')  // 获取当前角色的所有权限码, 自定义获取;
  if (Array.isArray(target)) {
    if (boolean) {
      return target.every(item => roles.indexOf(item) > -1)
    }
    return target.some(item => roles.indexOf(item) > -1)
  }
  return str && str.indexOf(target) > -1
}
4.菜单栏权限控制是否显示
/**
 * 菜单栏权限显示隐藏/现在很多架构都是自动化路由,有现成的权限配置
 * @param {Array} list 通过路由列表得到菜单列表
 * @returns {Array}
 * @description 通过用户权限控制的菜单列表(简易版)
 */
export const hasChild = (item) => {
  return item.children && item.children.length !== 0
}
export const getMenuByAside = (list) => {
  let res = [];
  list.forEach(item => {
    if (!item.access || authority(item.access)) {
      let obj = {
        title: item.title,
        index: item.index,
        icon: item.icon,
        access: item.access || undefined,
      }
      if (hasChild(item)) obj.children = getMenuByAside(item.children)
      if (hasChild(item) && authority(item.access)) {
        obj.children = getMenuByAside(item.children)
      }
      res.push(obj)
    }
  })
  return res
}
5.二维数组转换
/**
 * @param {Array} target 目标数组
 * @param {String} key 目标key值
 * @param {Boolean} boolean 是否需要数组转换
 * @param {Object} option 匹配的对象key值,值:label/value/boolean
 * @return {Array}
 * @description 处理二维数组转一维数组匹配相关字段值
 */
export const reduceConcat = (target, key, boolean, option) => {
  let newTarget = [];
  const { label, bool, value } = option || {};
  newTarget = target && target.map(item => {
    if (boolean) {
      return item[key] && item[key].map(opt => ({
        ...item,
        [key]: opt,
        [label]: bool ? item[label][value] : item[label]
      }))
    }
    return item[key];
  }
  ).reduce((a, b) => a.concat(b));
  return newTarget || [];
}
7. 针对json数组对象的去重
/**
 * @param {Array} array 目标数据
 * @param {String} label 匹配对象的字段
 * @description 针对json数组对象的去重
 */
export function uniqueArray(array, label) {
  const obj = {};
  array = array.reduce((pre, next) => {
    !obj[next[label]] ? (obj[next[label]] = true && pre.push(next)) : "";
    return pre;
  }, []);
  return array;
}
6. 时间类
// 转换时间(时分秒)
/**
 * @param {Number|String} msd 转换时间戳
 * @description 将时间戳转换成时分秒
 */
export function dealTimeToText(value) {
  let time = Math.floor(value / 1000)
  let h = Math.floor(Math.floor(time / 60) / 60)
  let min = Math.floor(time / 60) % 60
  let s = Math.round(time % 3600 % 60)
  if (h > 0) {
    return `${h}h${min}min${s}s`
  } else if (min > 0) {
    return `${min}min${s}s`
  } else {
    return `${s}s`
  }
}
  • 秒转时分秒
// 当天晚上23:59:59
const endTime = new Date(new Date(new Date().toLocaleDateString()).getTime() + 24 * 60 * 60 * 1000 - 1);
// 一月时间
let start = new Date();
start.setMonth(start.getMonth() - 3);
return start.getTime() > time.getTime() || time.getTime() > endTime;

// 一周时间
const operateTime = [
  new Date(new Date().toLocaleDateString()).getTime() - 7 * 24 * 3600 * 1000,
  new Date().setHours("23", "59", "59")
];

/**
 * @param {Number|String} value
 * @description 秒数转化为时分秒
*/
export const formatSeconds = (value) => {
  let secondTime = parseInt(value), minuteTime = 0, hourTime = 0;
  if (secondTime > 60) {
    minuteTime = parseInt(secondTime / 60);
    secondTime = parseInt(secondTime % 60);
    if (minuteTime > 60) {
      hourTime = parseInt(minuteTime / 60);
      minuteTime = parseInt(minuteTime % 60);
    }
  }
  let result = "" + parseInt(secondTime) + "秒";
  if (minuteTime > 0) {
    result = "" + parseInt(minuteTime) + "分" + result;
  }
  if (hourTime > 0) {
    result = "" + parseInt(hourTime) + "小时" + result;
  }
  return result;
}
  • 计算当前年龄
/** 
 * @param {String} dateTime 接收的日期eg: 1994-03-2 || 1569404854000
 * @description 通用年龄计算公式
 * */
import moment from 'moment';
export const getAgeYear = (dateTime) => {
  let reg = /^(\d{4})-(\d{1,2})-(\d{1,2})$/
  let time = !reg.test(dateTime) ? moment(dateTime, 'YYYY-MM-DD') : dateTime;
  let regexp = time.match(/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/);
  if (!regexp) return '';
  let date = new Date(regexp[1], regexp[3] - 1, regexp[4]);
  if (date.getFullYear() == regexp[1] && (date.getMonth() + 1) == regexp[3]
    && date.getDate() == regexp[4]) {
    let year = new Date().getFullYear();
    return year - regexp[1];
  }
}
  • 时间转换
/**
 * @param {Number} timelong 时间戳
 * @param {String} format 格式类型
 * @description 时间转换格式方法
 * */
export const formatDate = (timelong, format = 'YYYY-MM-DD') => {
  function format2n(val) {
    return val < 10 ? '0' + '' + val : val;
  }
  let date = new Date(timelong);
  let year = date.getFullYear() + '';
  let month = format2n(date.getMonth() + 1) + '';
  let day = format2n(date.getDate()) + '';
  let hour = format2n(date.getHours()) + '';
  let minute = format2n(date.getMinutes()) + '';
  let second = format2n(date.getSeconds()) + '';
  return format.replace(/YYYY/g, year).replace(/YYY/g, year.slice(1)).replace(/YY/g, year.slice(2)).replace(/Y/g, year.slice(1)).replace(/MM/g, month).replace(/M/g, month.slice(1)).replace(/DD/g, day).replace(/D/g, day.slice(1)).replace(/hh/g, hour).replace(/h/g, hour.slice(1)).replace(/mm/g, minute).replace(/m/g, minute.slice(1)).replace(/ss/g, second).replace(/s/g, second.slice(1));
};

/**
 * @param {Number} timelong 时间戳
 * @description 显示时间之前
 * */

export const formatTimeAgo = (timelong) => {
  const nowtime = new Date().getTime();
  let diffValue = nowtime - timelong;
  const bs = (diffValue >= 0 ? '前' : '后'); // 判断时间点是在当前时间的 之前 还是 之后
  diffValue = Math.abs(diffValue);
  if (diffValue < 6e4) { return '刚刚' } // 小于60秒,刚刚
  if (diffValue < 36e5) { return parseInt(diffValue / 6e4) + '分钟' + bs } // 小于1小时,按分钟
  if (diffValue < 864e5) { return parseInt(diffValue / 36e5) + '小时' + bs } // 小于1天按小时
  if (diffValue > 864e5 && diffValue < 1728e5) { return '昨天' } // 大于24小时小于48小时
  if (diffValue > 1728e5 && diffValue < 31536e6) { return formatDate(timelong, 'MM-DD') } // 大于48小时小于365天
  return formatDate(timelong, 'YYYY-MM-DD')
}
7.随机生成16进制颜色值,并改变状态
// 组件渲染后,500毫秒改变一次组件颜色
componentDidMount() {
	this.interval = setInterval(this.getRandomColor, 500);
}
getRandomColor = () => {
	this.setState({ 
		col: '#'+('00000'+(Math.random()*0x1000000<<0).toString(16)).slice(-6),
	});
}
8.背景水印简易版
/** 
 * @param {str} 用户需要显示的水印信息
 * @description 背景水印
 * */
export function addWaterMarker(str) {
  const can = document.createElement('canvas');
  // const { body } = document;
  // body.appendChild(can);
  can.width = 200;
  can.height = 100;
  can.style.display = 'none';
  const cans = can.getContext('2d');
  cans.rotate(20 * Math.PI / 180);
  cans.font = '16px Microsoft JhengHei';
  cans.fillStyle = 'rgba(17, 17, 17, 0.50)';
  cans.textAlign = 'left';
  cans.textBaseline = 'Middle';
  cans.fillText(str, can.width / 3, can.height / 2);
  return `url(${can.toDataURL('image/png')})`;
}

/**
* url转base64
*/
urlToBase64(url) {
    return new Promise((resolve, reject) => {
      let canvas = document.createElement("canvas"),
        ctx = canvas.getContext("2d"),
        img = new Image();
      img.crossOrigin = "Anonymous";
      img.src = url;
      img.onload = () => {
        canvas.width = img.width;
        canvas.height = img.height;
        ctx.drawImage(img, 0, 0, img.width, img.height);
        let dataUrl = canvas.toDataURL("image/jpeg");
        canvas = null;
        resolve(dataUrl);
      };
    });
  },
9.常用code码统一报错提示
const codeMessage = {
  200: '服务器成功返回请求的数据。',
  201: '新建或修改数据成功。',
  202: '一个请求已经进入后台排队(异步任务)。',
  204: '删除数据成功。',
  400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
  401: '用户没有权限(令牌、用户名、密码错误)。',
  403: '用户得到授权,但是访问是被禁止的。',
  404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
  406: '请求的格式不可得。',
  410: '请求的资源被永久删除,且不会再得到的。',
  422: '当创建一个对象时,发生一个验证错误。',
  500: '服务器发生错误,请检查服务器。',
  502: '网关错误。',
  503: '服务不可用,服务器暂时过载或维护。',
  504: '网关超时。',
};
10.原生ajax下载导出
/**
 * @param {String} url 下载URL地址
 * @param {String|Number} downloadName 下载文件名称
 * @Parma {type} 下载请求方法get||post
 * @description 导出Excel文件
 *  */
import Vue from 'vue';
import moment from 'moment';
import Cookies from "js-cookie";
const that = new Vue();

export function fileDownload(url, downloadName = moment(new Date(), 'YYYY-MM-DD') + "任务监控数据表", option) {
  const { type, status, message, messageErr, params } = option;

  let fileName = downloadName + '.xlsx';

  let request = new XMLHttpRequest();

  status ? that.$message({
    type: 'warning',
    showClose: true,
    message: message || '已点击正在下载,请稍后...',
  }) : null;

  request.open(type || 'GET', url, true);

  request.setRequestHeader("Authorization", Cookies.get("user-token"));

  request.setRequestHeader(
    "Content-Type",
    params ? 'application/json' : "application/x-www-form-urlencoded; charset=UTF-8"
  );

  request.responseType = "blob";

  request.onload = function () {
    if (this.status === 200) {
      let blob = this.response;
      if (window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveBlob(blob, fileName);
      } else {
        let downloadLink = document.createElement("a");
        let contentTypeHeader = request.getResponseHeader("Content-Type");
        downloadLink.href = window.URL.createObjectURL(
          new Blob([blob], { type: contentTypeHeader })
        );
        downloadLink.download = fileName;
        document.body.appendChild(downloadLink);
        downloadLink.click();
        document.body.removeChild(downloadLink);
        window.URL.revokeObjectURL(downloadLink.href)
      }
    } else {
      that.$message({
        type: 'error',
        showClose: true,
        message: messageErr ||'文件下载失败...',
      });
    }
  };
  request.send(params ? JSON.stringify(params) : void null);
}
10.file文件转码
const toDataUrl = (blob) => {
	return new Promise(resolve => {
		let file = new FileReader();
		file.onload = event => {
			resolve(event.target.result);
			};
		file.readAsDataURL(blob);
	});
},
11. url参数加密
export const Base64 = {
  //加密
  encode(params) {
    return btoa(encodeURIComponent(params).replace(/%([0-9A-F]{2})/g,
      function toSolidBytes(match, option) {
        return String.fromCharCode('0x' + option);
      }));
  },
  //解密
  decode(params) {
    return decodeURIComponent(atob(params.replace(/\s/g, '+')).split('').map(option => '%' + ('00' + option.charCodeAt(0).toString(16)).slice(-2)).join(''));
  }
}

\s : 表示 space ,空格
+: 一个或多个
^: 开始,^\s,以空格开始 结束,\s$,以空格结束
|:或者
/g:global, 全局

12. 背景水印
'use strict'

const watermark = {};

/**
 * @param {String} str // 要设置的水印的内容
 * @param {String} container // 需要设置水印的容器 
 */
const id = '1.23452384164.123412415';

const setWatermark = (str, container) => {
  if (!container) return false;

  if (document.getElementById(id) !== null) { // 查看页面上有没有,如果有则删除
    const childelement = document.getElementById(id)
    childelement.parentNode.removeChild(childelement)
  }

  const containerWidth = container.offsetWidth // 获取父容器宽
  const containerHeight = Math.max(container.scrollHeight, document.body.clientHeight); // 获取父容器高
  container.style.position = 'relative' // 设置布局为相对布局

  const can = document.createElement('canvas') // 创建canvas元素(先制作一块背景图)
  can.width = 300 // 设置每一块的宽度
  can.height = 200 // 高度
  const cans = can.getContext('2d') // 获取canvas画布
  cans.rotate(20 * Math.PI / 180) // 逆时针旋转π/9
  cans.font = '14px Microsoft JhengHei'; // 设置字体
  cans.fillStyle = 'rgba(17, 17, 17, 0.2)' // 设置字体的颜色
  cans.textAlign = 'left' // 文本对齐方式
  cans.textBaseline = 'Middle' // 文本基线
  cans.fillText(str, can.width / 3, can.height / 2); // 绘制文字

  const div = document.createElement('div') // 创建一个div元素
  div.id = id // 设置id
  div.style.pointerEvents = 'none' // 取消所有事件
  div.style.top = '0px'
  div.style.left = '0px'
  div.style.position = 'absolute'
  div.style.zIndex = '10000'
  div.style.width = containerWidth + 'px'
  div.style.height = containerHeight + 'px'
  div.style.background = 'url(' + dataURLtoBlob(can.toDataURL('image/png')) + ')'
  container.appendChild(div) // 追加到页面
  return id
}

function dataURLtoBlob(dataurl) {
  let arr = dataurl.split(',');
  let mime = arr[0].match(/:(.*?);/)[1];
  let bstr = atob(arr[1]);
  let n = bstr.length;
  let u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return URL.createObjectURL(new Blob([u8arr], { type: mime }));
}

let _interval = null;

// 该方法只允许调用一次
watermark.set = (str, container) => {
  let id = setWatermark(str, container)
  _interval = setInterval(() => {
    if (document.getElementById(id) === null) {
      id = setWatermark(str, container)
    }
  }, 500)
  window.onresize = () => {  // 监听页面大小的变化
    setWatermark(str, container)
  }
}

export default watermark;
12. 随机生成颜色
  getArrRandomly() {
    const tagsColor = ["info", "warning", "danger", ""];
    var colorIndex = Math.floor(Math.random() * tagsColor.length);
    var color = tagsColor[colorIndex];
    tagsColor.splice(colorIndex, 1);
    return color;
  },
13. 倒计时
startTime(bolean, endTimer) {
    let minute = 0
    let second = 0
    const that = this
    if (endTimer) {
      ;[minute, second] = this.callinTime.split(':')
      minute = Number(minute)
      second = Number(second)
    }
    if (bolean === true) {
      that.timer = setInterval(() => {
        if (second >= 0) {
          second = second + 1
        }
        if (second >= 60) {
          second = 0
          minute = minute + 1
        }
        if (endTimer && that.callinTime === endTimer) {
          this.suspendStatus = false
          this.callinTime = '00:00'
          return clearInterval(that.timer)
        }
        that.callinTime =
          (minute < 10 ? '0' + minute : minute) +
          ':' +
          (second < 10 ? '0' + second : second)
      }, 1000)
    } else {
      clearInterval(that.timer)
    }
  }
14. 金额转换
function toThousands(num) {
  if (num && num.toString().length > 4) {
    const result = num.toString().replace(/(\d)(?=(?:\d{4})+$)/g, '$1.')
    return Number(result).toFixed(1) + 'w'
  }
  return num
}
15. 页面滚动监听事件,实现滚动加载
// 页面滚动监听事件
export function scrollToBottom(callBack: any) {
  window.onscroll = () => {
    let scrollTop = 0
    let bodyScrollTop = 0
    let documentScrollTop = 0
    if (document.body) {
      bodyScrollTop = document.body.scrollTop
    }
    if (document.documentElement) {
      documentScrollTop = document.documentElement.scrollTop
    }
    scrollTop =
      bodyScrollTop - documentScrollTop > 0 ? bodyScrollTop : documentScrollTop
    let scrollHeight = 0
    let bodyScrollHeight = 0
    let documentScrollHeight = 0
    if (document.body) {
      bodyScrollHeight = document.body.scrollHeight
    }
    if (document.documentElement) {
      documentScrollHeight = document.documentElement.scrollHeight
    }
    // 获取文档元素的内容垂直滚动的像素数
    scrollHeight =
      bodyScrollHeight - documentScrollHeight > 0
        ? bodyScrollHeight
        : documentScrollHeight
    let windowHeight = 0
    // 判断当前文档的渲染模式是混杂模式还是"标准模式"
    if (document.compatMode === 'CSS1Compat') {
      // “标准模式”或者“准标准模式(almost standards mode)”
      windowHeight = document.documentElement.clientHeight
    } else {
      // 混杂模式,值为"BackCompat"
      windowHeight = document.body.clientHeight
    }
    // 若文档内容垂直滚动像素 + 当前窗口高度的像素 === document.body.scrollHeight或document.documentElement.scrollHeight返回Promise对象,执行后续操作
    if (scrollHeight - (scrollTop + windowHeight) < 1000) {
      callBack()
    }
  }
}

// 使用
scrollToBottom(() => {
   if (!this.loadMore) return false
   this.getDataList()
 })

16. 两数组重组json
// 数据匹配重组
  function filterDataList(data, targetArr, option) {
  	const { lable } = option
    const array = [];
    for (let i = 0; i < data.length; i++) {
      const item = data[i]
      array.push(item);
      for (let j = 0; j < targetArr.length; j++) {
        if (item[lable] === item[lable]) {
          array[i] = Object.assign({}, item, targetArr[j]); //合并对象
          targetArr.splice(j, 1); //删除本次合并的对象,增加性能
          break;
        }
      }
    }
    return array;
  }
17. 图片压缩
const MAX_SIZE = 10485760 //图片最大字节数

function compressImg(file, quality) {
  let reader = new FileReader()
  let image = new Image()
  let canvas = document.createElement('canvas');
  let context = canvas.getContext('2d');
  return new Promise(resolve => {
    reader.readAsDataURL(file) // 文件base64化,以便获知图片原始尺寸
    reader.onload = e => image.src = e.target.result;
    image.onload = _ => {
      let originWidth = image.width;
      let originHeight = image.height;
      let targetWidth = originWidth, targetHeight = originHeight;
      canvas.width = targetWidth;  // canvas对图片进行缩放
      canvas.height = targetHeight;
      context.clearRect(0, 0, targetWidth, targetHeight); // 清除画布
      context.drawImage(image, 0, 0, targetWidth, targetHeight); // 图片压缩
      canvas.toBlob(blob => {  //压缩后的图片base64 url  /*canvas.toDataURL(mimeType, qualityArgument),mimeType 默认值是'image/jpeg'; * qualityArgument表示导出的图片质量,只要导出为jpg和webp格式的时候此参数才有效果,默认值是0.92*/
        if (blob.size > MAX_SIZE) {
          alert('最大只允许上传10MB哦~')
          resolve()
        } else {
          resolve(blob)
        }
      }, 'image/jpeg', quality)
    }
  })
}

//计算压缩质量
function computedQuality(size, max, count = 1) {
  if (size >= max) {
    if (count > 1) {
      return 0.1 * count - .1
    } else {
      return 0.1 * count
    }
  } else {
    if (max - EVA <= 0) {
      return .9
    } else {
      return computedQuality(size, max - EVA, ++count)
    }
  }
}

18. 计算两个日期时间相差的年数、月数、天数、日期时间
/**
 * 计算两个日期时间相差的年数、月数、天数、日期时间
 * console.log(formatExpirationTime('2019-6-30', '2020-10-01'))
 */

export const formatExpirationTime = (startTime, endTime) => {
  function getDays(mouth, year) {
    let days = 30
    if (mouth === 2) {
      days = year % 4 === 0 ? 29 : 28
    } else if (
      mouth === 1 ||
      mouth === 3 ||
      mouth === 5 ||
      mouth === 7 ||
      mouth === 8 ||
      mouth === 10 ||
      mouth === 12
    ) {
      days = 31
    }
    return days
  }

  const start: any = new Date(startTime)
  const end: any = new Date(endTime)
  const diffValue = end - start

  const startYear = start.getFullYear()
  const endYear = end.getFullYear()
  const startMouth = start.getMonth() + 1
  const endMouth = end.getMonth() + 1
  const startDay = start.getDate()
  const endDay = end.getDate()
  const startHours = start.getHours()
  const endHours = end.getHours()
  const startMinutes = start.getMinutes()
  const endMinutes = end.getMinutes()
  const startSeconds = start.getSeconds()
  const endSeconds = end.getSeconds()

  if (diffValue >= 8.64e7 * 30) {
    const diffYear = endYear - startYear
    const startDays = getDays(startMouth, startYear)
    const endDays = getDays(endMouth, endYear)

    const diffStartMouth =
      (startDays - (startDay + (startHours * 60 + startMinutes + startSeconds / 60) / 60 / 24 - 1)) /
      startDays

    const diffEndMouth = (endDay + (endHours * 60 + endMinutes + endSeconds / 60) / 60 / 24 - 1) / endDays

    const diffMouth = diffStartMouth + diffEndMouth + (12 - startMouth - 1) + endMouth + (diffYear - 1) * 12

    if (diffValue >= 8.64e7 * 365) {
      const diffYear = Math.floor((diffMouth / 12) * 100) / 100
      const year = parseInt((((diffMouth / 12) * 100) / 100).toString())
      const mouth = (diffYear % year) * 12
      return year + '年' + (mouth ? mouth + '月' : '')
    } else {
      return Math.floor(diffMouth) + '月'
    }
  } else if (diffValue >= 8.64e7) {
    const d = parseInt((diffValue / 1000 / 60 / 60 / 24).toString())
    return d + '天'
  } else {
    return endTime
  }
}
19. bytesToSize
export const bytesToSize = (size) => {
  if (!size) return '0.00';
  const pow1024 = (num) => Math.pow(1024, num)
  if (size < pow1024(1)) return size + ' B';
  if (size < pow1024(2)) return (size / pow1024(1)).toFixed(2) + ' KB';
  if (size < pow1024(3)) return (size / pow1024(2)).toFixed(2) + ' MB';
  if (size < pow1024(4)) return (size / pow1024(3)).toFixed(2) + ' GB';
  return (size / pow1024(4)).toFixed(2) + ' TB'
}

20. 用js实现可终止的轮询请求

  1. 按照需要选择是否立即发起请求再进入轮询
  2. 上一次的请求响应后到了指定的时间间隔后再继续执行下一次请求
  3. 当轮询的请求发生报错的时候应该停止轮询
  4. 被停止的轮询可以根据需要再次发起轮询
/**
 * @descripting 轮询功能
 * @param {Function} callback 回调事件
 * @param {Number} interval 轮询间隔时间
 */
export const pollingHttp = (callback, interval = 2000) => {
  let timer, isStop = false

  const stop = () => {
    isStop = true
    clearTimeout(timer)
  }

  const start = async () => {
    isStop = false
    await loopEvent()
  }

  const loopEvent = async () => {
    try {
      await callback(stop)
    } catch (err) {
      throw new Error('轮询出错:', err)
    }
    if (isStop) return
    return (timer = setTimeout(loopEvent, interval))
  }

  return { start, stop }
}

模拟请求使用

import { pollingHttp } from '@/utils/utilTool'

const arr = ref<any[]>([])

const intervalManager = pollingHttp(async (stop) => {
  const res: any = await api.hostmanage({ curPage: 1, pageSize: 10 }, 'get')
  if (res?.code === 0) {
    const { data, durationSecond } = res.data
    arr.value.push(...data)
    console.log(arr, 'res')
    if (durationSecond === 100) {
	  stop()
	}
  }
 }
}, 3000)

21. 一维数组将相同id放置到一个对象内,组成新数组

  formatterDataSource(data) {
    const groupedData = data.reduce((acc, curr) => {
      const id = curr.graphType === 8 ? curr.serverMeta?.id : false ;
        if (!id) {
          return acc;
        }
        if (!acc[id]) {
          acc[id] = [];
        }
        acc[id].push(curr);
        return acc;
      }, {});

    const newData = Object.values(groupedData).map((group) => {
      if (group.length === 1) {
        return group[0];
      }
      const obj = { graphType: 11.11, ...group[0] };
      group.forEach((item, index) => {obj[index] = item });
      return obj;
    });

    return [ ...data, ...newData]
};

22. 获取天、周、本月、上月时间戳

getCurrentDateTime() {
    const currentNowDate = Math.round(Date.now() / 1000)

    const now = new Date();
    now.setHours(0, 0, 0, 0);
    const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1); // 当前月1号的时间戳
    const firstDayTimestamp = Math.floor(firstDayOfMonth.getTime() / 1000); // 当前月时间

    const lastMonthFirstDay = new Date(now.getFullYear(), now.getMonth() - 1, 1);
    const lastMonthLastDay = new Date(now.getFullYear(), now.getMonth(), 0);
    const lastMonthFirstDayTimestamp = Math.floor(lastMonthFirstDay.getTime() / 1000); // 上个月1号的时间戳
    const lastMonthLastDayTimestamp = Math.floor(lastMonthLastDay.getTime() / 1000) + 86400; // 上个月最后一天的时间戳

    this.startDateTime = {
      1: [currentNowDate - 8.64e4, currentNowDate],
      2: [currentNowDate - 8.64e4 * 7, currentNowDate],
      3: [firstDayTimestamp, currentNowDate],
      4: [lastMonthFirstDayTimestamp, lastMonthLastDayTimestamp]
    }
  },
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

前端常用工具库方法整理 的相关文章

随机推荐

  • 微信小程序水平居中,和垂直居中

    微信小程序水平居中 和垂直居中 1 WXML信息展示
  • Windows文本编辑器——推荐、介绍与安装(1)

    撰写时间 2023年4月11日 目的 介绍各种类型的文本编辑器 阐述编辑器的优缺点 并提供安装与使用方法 前言 文本编辑器是应用各种已有的编程语言进行软件开发的一种重要工具 它能够帮助开发者更加高效地编写代码 也能够帮助电脑小白快速上手各种
  • Qt Model View TreeView及对应Model

    点击上方蓝字可直接关注 方便下次阅读 如果对你有帮助 可以点个在看 让它可以帮助到更多老铁 一 概述 接着之前的话题继续 如果把之前的QTableView改成QTreeView 我们在不改变Model的情况下可以直接得到一个没有结构层次的
  • Linux KVM 使用教程(一)

    文章目录 1 KVM简介 2 KVM 的功能列表 3 KVM 工具集合 3 1 Virsh命令 1 KVM简介 1 KVM 全称是 基于内核的虚拟机 Kernel based Virtual Machine 它是Linux 的一个内核模块
  • python2(基本)

    实验02 基本 一 课内实验题 共10小题 100分 题型得分 100 描述 编写程序 从键盘输入两个整数 计算并输出这两个整数的和 平均值 最小值和最大值 平均值保留2位小数 输入 分行输入两个整数 输出 分行输出两个整数的和 平均值 最
  • JDK1.8 下载与安装

    JDK安装 JDK1 8下载 下载链接 https www oracle com java technologies javase javase jdk8 downloads html 根据操作系统版本下载 这里以win10 64位操作系统
  • 驱动程序里ioctl下switch问题

    今天在写步进电机驱动程序时 switch语句引出3个分支 case 0 case 1 case 2 case 0 什么都不做 case 1让步进电机正向转动 case 2让步进电机反向转动 但是测试时 case 2怎么也动不起来 后来把ca
  • PLSQL Developer的配置方法

    1 下载32位的版本instantclient basic nt 11 2 0 3 0 zip 因为PLSQLDev是32位的 没有64位的版本 这 个和操作系统无关 2 instantclient下载完后是一个压缩文件 不需要安装 配置一
  • 服务器系统如何清理,服务器清理内存怎么清理

    服务器清理内存怎么清理 内容精选 换一换 本节操作指导您完成Windows操作系统云服务器磁盘空间清理 弹性云服务器匀出一部分磁盘空间来充当内存使用 当内存耗尽时 云服务器可以使用虚拟内存来缓解内存的紧张 但当内存使用率已经非常高时 频繁的
  • 关于HTTP协议,一篇就够了

    HTTP简介 HTTP协议是Hyper Text Transfer Protocol 超文本传输协议 的缩写 是用于从万维网 WWW World Wide Web 服务器传输超文本到本地浏览器的传送协议 HTTP是一个基于TCP IP通信协
  • TCP 连接管理机制(一)——TCP三次握手详解 + 为什么要有三次握手

    TCP是面向连接的协议 在通信之前需要先建立连接 其本质就是打开一个socket文件 这个文件有自己的缓冲区 如果要发送数据 上层把数据拷贝到发送缓冲区 如果是接收数据 OS直接把来自网络的数据拷贝到接收缓冲区里 那么三次握手期间 Serv
  • youversion.com的圣经无法使用、无法连接、无法下载离线版本的解决方法

    最近 youversion com的圣经无法使用 无法连接 无法下载离线版本了 这是一部很好用的圣经软件 以前一直用着 后来ipad越狱重新安装的时候就不能连接了 后来无意间发现原来是这个网站被和谐了 至于GCD为什么这么做 以咱的智商尚不
  • 接口自动化测试须知

    一 做接口测试需要哪些技能 做接口测试 需要的技能 基本就是以下几点 业务流 了解系统及内部各个组件之间的业务逻辑交互 数据流 了解接口的I O input output 输入输出 协议 包括http协议 TCP IP协议族 http协议
  • CMD查杀端口的两种方式

    第一种 netstat ano windows r输入cmd并打开 输入netstat ano 记住对应的6052 输入杀掉端口 taskkill pid 6052 f 第二种 netstat aon findstr 8080 直接输入ne
  • Win10 + VS2017 + Ceres配置

    前言 Ceres是google出品的一款基于C 的开源非线性优化库 官方文档 Ceres官方文档地址 依赖库 Eigen 官网 glog github gflags github Ceres github 配置过程 1 Eigen Eige
  • Python3 爬虫 requests+BeautifulSoup4(BS4) 爬取小说网站数据

    刚学Python爬虫不久 迫不及待的找了一个网站练手 新笔趣阁 一个小说网站 前提准备 安装Python以及必要的模块 requests bs4 不了解requests和bs4的同学可以去官网看个大概之后再回来看教程 爬虫思路 刚开始写爬虫
  • GPT专业应用:快速生成职位描述(JD)

    正文共 814 字 阅读大约需要 3 分钟 人力资源必备技巧 您将在3分钟后获得以下超能力 快速生成职位描述 Beezy评级 B级 经过简单的寻找 大部分人能立刻掌握 主要节省时间 推荐人 Kim 编辑者 Linda 图片由 Lexica
  • 数据中台与传统大数据平台有什么区别?_光点科技

    一 数据中台 数据中台是聚合和治理跨域数据 将数据抽象封装成服务 提供给前台以业务价值的逻辑概念 数据中台是在平台概念上的升级 不再单纯的将功能进行大杂烩 理念上 中台有几个特点 第一 更强调数据集中存储 统一管理 提供标准化的服务 第二
  • 【毕业设计】基于springboot + vue微信小程序商城

    目录 前言 创新点 亮点 毕设目录 一 视频展示 二 系统介绍 三 项目地址 四 运行环境 五 设计模块 前台 后台 六 系统功能模块结构图 数据库设计 七 准备阶段 使用真实支付 使用模拟支付 八 使用说明 九 登录后台 十 后台页面展示
  • 前端常用工具库方法整理

    欢迎点击领取 前端面试题进阶指南 前端登顶之巅 最全面的前端知识点梳理总结 前言 在闲余的时间整理一份我们可能用到的前端工具库方法 依赖库 名称 cropperjs 图片裁剪 exif js lrz 图片旋转问题 html2canvas d