utils

370 阅读5分钟

设备、浏览器

url

根据name获取url参数

function getQueryString(name) {
    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
    var r = window.location.search.substr(1).match(reg);
    if (r != null) return unescape(r[2]);
    return null;
}

获取URL参数列表

export const GetRequest = () => {
    let url = location.search;
    const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 将 ? 后面的字符串取出来
    const paramsArr = paramsStr.split('&'); // 将字符串以 & 分割后存到数组中
    let paramsObj = {};
    // 将 params 存到对象中
    paramsArr.forEach(param => {
      if (/=/.test(param)) { // 处理有 value 的参数
        let [key, val] = param.split('='); // 分割 key 和 value
        val = decodeURIComponent(val); // 解码
        val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字
        if (paramsObj.hasOwnProperty(key)) { // 如果对象有 key,则添加一个值
          paramsObj[key] = [].concat(paramsObj[key], val);
        } else { // 如果对象没有这个 key,创建 key 并设置值
          paramsObj[key] = val;
        }
      } else { // 处理没有 value 的参数
        paramsObj[param] = true;
      }
    })
    return paramsObj;
};

检测URL是否有效

export const getUrlState = (URL) => {
  let xmlhttp = new ActiveXObject("microsoft.xmlhttp");
  xmlhttp.Open("GET", URL, false);
  try {
    xmlhttp.Send();
  } catch (e) {
  } finally {
    let result = xmlhttp.responseText;
    if (result) {
      if (xmlhttp.Status == 200) {
        return true;
      } else {
        return false;
      }
    } else {
      return false;
    }
  }
}

键值对拼接成URL参数

export const params2Url = (obj) => {
     let params = []
     for (let key in obj) {
       params.push(`${key}=${obj[key]}`);
     }
     return encodeURIComponent(params.join('&'))
}

修改URL中的参数

export const replaceParamVal => (paramName, replaceWith) {
   const oUrl = location.href.toString();
   const re = eval('/('+ paramName+'=)([^&]*)/gi');
   location.href = oUrl.replace(re,paramName+'='+replaceWith);
   return location.href;
}

删除URL中指定参数

export const funcUrlDel = (name) => {
  const baseUrl = location.origin + location.pathname + "?";
  const query = location.search.substr(1);
  if (query.indexOf(name) > -1) {
    const obj = {};
    const arr = query.split("&");
    for (let i = 0; i < arr.length; i++) {
      arr[i] = arr[i].split("=");
      obj[arr[i][0]] = arr[i][1];
    }
    delete obj[name];
    return baseUrl + JSON.stringify(obj).replace(/[\"\{\}]/g,"").replace(/\:/g,"=").replace(/\,/g,"&");
  }
}

窗口

刘海屏安全距离解决方案

iOS11 新增特性中,Webkit 包含了两个新的函数 env()constant(),以及四个预定义的常量:

  • safe-area-inset-top:安全区域距离顶部边界距离,状态栏+导航栏大约为88px。
  • safe-area-inset-left:安全区域距离左边边界距离,竖屏时为0。
  • safe-area-inset-right:安全区域距离右边边界距离,竖屏时为0。
  • safe-area-inset-bottom:安全区域距离底部边界距离,大约高度为34px。

我们可以这样子使用它们:

/*注意:constant必须写在前面,env写在后面。*/
body{
    /* 兼容 iOS < 11.2 */
    padding-top: constant(safe-area-inset-top);
    padding-left: constant(safe-area-inset-left);
    padding-right: constant(safe-area-inset-right);
    padding-bottom: constant(safe-area-inset-bottom);
    /* 兼容 iOS >= 11.2 */
    padding-top: env(safe-area-inset-top);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
    padding-bottom: env(safe-area-inset-bottom);
}
// 当然,你也可以在某个固定(fixed)在底部的元素上单独使用
div{
    padding-bottom: constant(safe-area-inset-bottom);
    padding-bottom: env(safe-area-inset-bottom);
}

滚动到页面顶部

export const scrollToTop = () => {
  const height = document.documentElement.scrollTop || document.body.scrollTop;
  if (height > 0) {
    window.requestAnimationFrame(scrollToTop);
    window.scrollTo(0, height - height / 8);
  }
}

滚动到页面底部

export const scrollToBottom = () => {
  window.scrollTo(0, document.documentElement.clientHeight);  
}

滚动到指定元素区域

export const smoothScroll = (element) => {
    document.querySelector(element).scrollIntoView({
        behavior: 'smooth'
    });
};

获取可视窗口高度

export const getClientHeight = () => {
    let clientHeight = 0;
    if (document.body.clientHeight && document.documentElement.clientHeight) {
        clientHeight = (document.body.clientHeight < document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight;
    }
    else {
        clientHeight = (document.body.clientHeight > document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight;
    }
    return clientHeight;
}

获取可视窗口宽度

export const getPageViewWidth = () => {
    return (document.compatMode == "BackCompat" ? document.body : document.documentElement).clientWidth;
}

打开浏览器全屏

export const toFullScreen = () => {
    let element = document.body;
    if (element.requestFullscreen) {
      element.requestFullscreen()
    } else if (element.mozRequestFullScreen) {
      element.mozRequestFullScreen()
    } else if (element.msRequestFullscreen) {
      element.msRequestFullscreen()
    } else if (element.webkitRequestFullscreen) {
      element.webkitRequestFullScreen()
    }
}

退出浏览器全屏

export const exitFullscreen = () => {
    if (document.exitFullscreen) {
      document.exitFullscreen()
    } else if (document.msExitFullscreen) {
      document.msExitFullscreen()
    } else if (document.mozCancelFullScreen) {
      document.mozCancelFullScreen()
    } else if (document.webkitExitFullscreen) {
      document.webkitExitFullscreen()
    }
}

滚动窗口回调

export function handleScrollHeader(callback) {
    let timer = 0

    let beforeScrollTop = window.pageYOffset
    callback = callback || function() {}
    window.addEventListener(
        'scroll',
        event => {
            clearTimeout(timer)
            timer = setTimeout(() => {
                let direction = 'up'
                const afterScrollTop = window.pageYOffset
                const delta = afterScrollTop - beforeScrollTop
                if (delta === 0) {
                    return false
                }
                direction = delta > 0 ? 'down' : 'up'
                callback(direction)
                beforeScrollTop = afterScrollTop
            }, 50)
        },
        false
    )
}

自动打开新窗口下载

export function download(url: string, name ? : string) {
    const a = document.createElement('a');
    const isSupportDownload = 'download' in a;

    if (isSupportDownload) {
        a.href = url;
        if (name) {
            a.download = name;
        }
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    } else {
        window.open(url);
    }
}

判断功能支持

浏览器是否支持全屏 全屏状态

export function supportFullScreen() {
    const doc = document.documentElement
    return ('requestFullscreen' in doc) ||
        ('mozRequestFullScreen' in doc && document.mozFullScreenEnabled) ||
        ('msRequestFullscreen' in doc && document.msFullscreenEnabled) ||
        ('webkitRequestFullScreen' in doc)
}

export function fullScreenStatus() {
    if (document.fullscreen ||
        document.mozFullScreen ||
        document.fullscreenElement ||
        document.msFullscreenElement ||
        document.webkitIsFullScreen) {
        return true
    } else {
        return false
    }
}

判断环境

获取浏览器型号和版本

export const getExplorerInfo = () => {
    let t = navigator.userAgent.toLowerCase();
    return 0 <= t.indexOf("msie") ? { //ie < 11
        type: "IE",
        version: Number(t.match(/msie ([\d]+)/)[1])
    } : !!t.match(/trident\/.+?rv:(([\d.]+))/) ? { // ie 11
        type: "IE",
        version: 11
    } : 0 <= t.indexOf("edge") ? {
        type: "Edge",
        version: Number(t.match(/edge\/([\d]+)/)[1])
    } : 0 <= t.indexOf("firefox") ? {
        type: "Firefox",
        version: Number(t.match(/firefox\/([\d]+)/)[1])
    } : 0 <= t.indexOf("chrome") ? {
        type: "Chrome",
        version: Number(t.match(/chrome\/([\d]+)/)[1])
    } : 0 <= t.indexOf("opera") ? {
        type: "Opera",
        version: Number(t.match(/opera.([\d]+)/)[1])
    } : 0 <= t.indexOf("Safari") ? {
        type: "Safari",
        version: Number(t.match(/version\/([\d]+)/)[1])
    } : {
        type: t,
        version: -1
    }
}

判断是移动还是PC设备

export const isMobile = () => {
  if ((navigator.userAgent.match(/(iPhone|iPod|Android|ios|iOS|iPad|Backerry|WebOS|Symbian|Windows Phone|Phone)/i))) {
  return 'mobile';
  }
  return 'desktop';
}

判断是否是isIE

export function isIE() {
    const bw = window.navigator.userAgent
    const compare = (s) => bw.indexOf(s) >= 0
    const ie11 = (() => 'ActiveXObject' in window)()
    return compare('MSIE') || ie11
}

判断是Windows还是Mac系统

export const osType = () => {
    const agent = navigator.userAgent.toLowerCase();
    const isMac = /macintosh|mac os x/i.test(navigator.userAgent);
   const isWindows = agent.indexOf("win64") >= 0 || agent.indexOf("wow64") >= 0 || agent.indexOf("win32") >= 0 || agent.indexOf("wow32") >= 0;
    if (isWindows) {
        return "windows";
    }
    if(isMac){
        return "mac";
    }
}

判断是否是微信/QQ内置浏览器

export const broswer = () => {
    const ua = navigator.userAgent.toLowerCase();
    if (ua.match(/MicroMessenger/i) == "micromessenger") {
        return "weixin";
    } else if (ua.match(/QQ/i) == "qq") {
        return "QQ";
    }
    return false;
}

判断是否是苹果还是安卓移动设备

export const isAppleMobileDevice = () => {
  let reg = /iphone|ipod|ipad|Macintosh/i;
  return reg.test(navigator.userAgent.toLowerCase());
}

分辨率/像素

当前设备分辨率 像素/英寸

/**
 * 当前设备分辨率 像素/英寸
 * @return {Array}
 */
 function getDPI(){
        var arrDPI = new Array;
        // IE支持此属性
        if (window.screen.deviceXDPI) {
            arrDPI[0] = window.screen.deviceXDPI;
            arrDPI[1] = window.screen.deviceYDPI;
        } else {
            var tmpNode = document.createElement("DIV");
            tmpNode.style.cssText = "width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden";
            document.body.appendChild(tmpNode);
            arrDPI[0] = parseInt(tmpNode.offsetWidth);
            arrDPI[1] = parseInt(tmpNode.offsetHeight);
            tmpNode.parentNode.removeChild(tmpNode);
        }

        return arrDPI;
    }

获取A4纸在屏幕中的像素宽高

/**
 * 获取A4纸在屏幕中的像素宽高
 * @return {Object}
 */
function getA4PixelSize() {
    var deviceXDPI = this.getDPI()[0];
    var a4_PixelWidth = 210 / 25.4 * deviceXDPI;
    var a4_PixelHeight = 297 / 25.4 * deviceXDPI;

    return {
        width: a4_PixelWidth,
        height: a4_PixelHeight
    };
}

格式/类型

类型转换\判断

数据类型判断

export const getType = (value) => {
  if (value === null) {
    return value + "";
  }
  // 判断数据是引用类型的情况
  if (typeof value === "object") {
    let valueClass = Object.prototype.toString.call(value),
      type = valueClass.split(" ")[1].split("");
    type.pop();
    return type.join("").toLowerCase();
  } else {
    // 判断数据是基本数据类型的情况和函数的情况
    return typeof value;
  }
}

映射表转数组

function mapToArray(map, nameKey = "label", valueKey = "value") {
  //缺少一个map为非for循环值的判断
  const reval = []
  for (const key in map) {
    const label = map[key];
    reval.push({
      [nameKey]: label,
      [valueKey]: key,
    })
  }
  return reval
}

blob类型转换到dataURL数据

/**
 * blob类型转换到dataURL数据
 * @param {Object} blob 
 * @param {Function} callback 转换完成后回调方法,参数:转换后的结果
 */
blobToDataURL: function(blob, callback) {
    var a = new FileReader();
    a.onload = function(e) {
        callback(e.target.result);
    }
    a.readAsDataURL(blob);
}

格式/单位转换

转浮点数

/**
 * 保留小数位数
 * @param value 值
 * @param dec 小数位数
 * @param divisor 倍数
 * @param defaultValue 无数据时返回值
 */
export function fixNumber(value: any, dec = 2, divisor = 1, defaultValue = '--') {
    if (isNil(value) || Number.isNaN(+value)) return defaultValue;
    return (+value / divisor).toFixed(dec);
}

转百分比

export function fixPercentage(value, dec = 1, defaultValue = '--') {
    if (_.isNil(value) || Number.isNaN(+value) || (typeof value === 'string' && value.length === 0)) return defaultValue;
    const n = (+value).toFixed(dec);
    return `${n}%`;
}

金额逢3逗号切割 例如1, 100, 000.23

/*
 * @description: 金额格式化 例如1,100,000.23
 * @param: value:金额 dec:小数点后位数
 * @author: Waker
 */
amountFormat(value: string | number, dec: number = 0) {
    const s = Number(value).toFixed(dec);
    const l = s.split(".")[0].split("").reverse()
    const r = '.' + s.split(".")[1];
    let t = "";
    for (let i = 0; i < l.length; i++) {
        t += l[i] + ((i + 1) % 3 == 0 && (i + 1) != l.length ? "," : "");
    }

    const reStr = dec === 0 ?
        t.split("").reverse().join("") :
        t.split("").reverse().join("") + r
    return reStr;
}

隐私字段用*转换

/*
 * @description: 隐私字段用*转换 例如aaaa****bbbb
 * @param: value:文本 
 * @author: Waker
 */
hideString(value, before, after) {
    if (!value) {
        return;
    }
    value = String(value);
    let beforeStr = value.substr(0, before);
    let afterStr = after ? value.substr(-after) : '';
    let hideLen = value.length - before - after;

    let reVal = beforeStr + '*'.repeat(hideLen) + afterStr;
    return reVal; //将格式化后的字符串输出到前端显示
},

格式化银行卡号 目前规则为 4个字符加一个空格

/**
 *  格式化银行卡号 目前规则为 4个字符加一个空格
 *
 *  @param bankCardCode   银行卡号
 */
function fomartBankCardCode(bankCardCode) {

    //遍历账户
    let spaceStr = "";
    for (let i = 0, len = bankCardCode.length; i < len; i++) {
        //每4个字符加一个空格
        if (i % 4 === 0) {
            spaceStr += " " + bankCardCode[i];
        } else {
            spaceStr += bankCardCode[i];
        }
    }
    return spaceStr;
}

金额转大写

/**
 * 毫秒转 天时分秒
 * @param mss
 * @return {string}
 */
function changeMoneyToChinese(n) {
    var fraction = ['角', '分'];
    var digit = [
        '零', '壹', '贰', '叁', '肆',
        '伍', '陆', '柒', '捌', '玖'
    ];
    var unit = [
        ['元', '万', '亿'],
        ['', '拾', '佰', '仟']
    ];
    var head = n < 0 ? '欠' : '';
    n = Math.abs(n);
    var s = '';
    for (var i = 0; i < fraction.length; i++) {
        s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');
    }
    s = s || '整';
    n = Math.floor(n);
    for (var i = 0; i < unit[0].length && n > 0; i++) {
        var p = '';
        for (var j = 0; j < unit[1].length && n > 0; j++) {
            p = digit[n % 10] + unit[1][j] + p;
            n = Math.floor(n / 10);
        }
        s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
    }
    return head + s.replace(/(零.)*零元/, '元')
        .replace(/(零.)+/g, '零')
        .replace(/^整$/, '零元整');
}

数字转化为中文数字

export const intToChinese = (value) => {
 const str = String(value);
 const len = str.length-1;
 const idxs = ['','十','百','千','万','十','百','千','亿','十','百','千','万','十','百','千','亿'];
 const num = ['零','一','二','三','四','五','六','七','八','九'];
 return str.replace(/([1-9]|0+)/g, ( $, $1, idx, full) => {
    let pos = 0;
    if($1[0] !== '0'){
      pos = len-idx;
      if(idx == 0 && $1[0] == 1 && idxs[len-idx] == '十'){
        return idxs[len-idx];
      }
      return num[$1[0]] + idxs[len-idx];
    } else {
      let left = len - idx;
      let right = len - idx + $1.length;
      if(Math.floor(right / 4) - Math.floor(left / 4) > 0){
        pos = left - left % 4;
      }
      if( pos ){
        return idxs[pos] + num[$1[0]];
      } else if( idx + $1.length >= len ){
        return '';
      }else {
        return num[$1[0]]
      }
    }
   });
}

金额单位转成:元/万元/亿元等

/**
 * 金额格式化方法  只有万元
 * @param {*} value //要格式化的值
 * @param {*} pos //小数点位数
 */
export function numberFormat(value, k = 10000) {
    if (!value) {
        return {
            value: 0,
            unit: '元',
        }
    }
    var param = {}
    var sizes = ['元', '万元', '亿元', '万亿元']
    if (value < k) {
        param.value = toFixed(value)
        param.unit = '元'
    } else {
        let i = Math.floor(Math.log(value) / Math.log(k))
        param.value = ((value / Math.pow(k, i))).toFixed(2)
        param.unit = sizes[i]
    }
    return param
}

空间/坐标/地理操作

反查省市区

//反查省市区
reAreaCode(val) {
    if (!val) {
        return;
    }
    let a = val.slice(0, 2) + '0000';
    let b = val.slice(0, 4) + '00';
    let c = val;
    let code;

    // a === '820000' ? code = [a, c] : code = [a, b, c];
    return [a, b, c];
},

已知两点坐标, 求中心点垂直线的顶点坐标(常用来做贝塞尔曲线的顶点)

function computedP3(p1, p2) {
    // 短轴半径 
    const P1X = p1[0];
    const P1Y = p1[1];

    const P2X = p2[0];
    const P2Y = p2[1];

    // n为垂直线到顶点的距离 0.3为系数,可修改,系数越大贝塞尔曲线的弧度越大
    const n = Math.sqrt(Math.pow((P2X - P1X), 2) + Math.pow((P2Y - P1Y), 2)) * 0.3;

    // tan角度
    const TANangle = (P1X - P2X) / (P2Y - P1Y);

    // 计算点 相对中心点的高度
    const Fed = Math.sqrt(Math.pow(TANangle, 2) / (Math.pow(TANangle, 2) + 1)) * n;
    const Fec = Math.sqrt(1 / (Math.pow(TANangle, 2) + 1)) * n;

    let P3X = ((P1X + P2X) / 2) + Fec;
    let P3Y = ((P1Y + P2Y) / 2) + Fed;

    return [P3X, P3Y];
}

判断坐标范围是否超出中国范围

/**
 * 判断坐标范围是否超出中国范围
 *
 * @param {Number} lon 经度
 * @param {Number} lat 纬度
 *
 * @return {Boolean}
 */
outOfChina: function(lon, lat) {
    if (lon < 72.004 || lon > 137.8347)
        return true;
    if (lat < 0.8293 || lat > 55.8271)
        return true;
    return false;
},

地理坐标系转换

/**
 * wgs84坐标转火星坐标(偏差坐标)
 * @param {float} wgLon wgs经度
 * @param {float} wgLat wgs纬度
 * @return {Array} 加了偏差后的坐标
 */
convertLonLatToGCJ: function(wgLon, wgLat) {
        var a = 6378245.0;
        var ee = 0.00669342162296594323;
        var mgLat, mgLon;
        if (util.outOfChina(wgLon, wgLat)) {
            mgLon = wgLon;
            mgLat = wgLat;
            return;
        }
        var dLat = util.transformLat(wgLon - 105.0, wgLat - 35.0);
        var dLon = util.transformLon(wgLon - 105.0, wgLat - 35.0);
        var radLat = wgLat / 180.0 * Math.PI;
        var magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        var sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * Math.PI);
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * Math.PI);
        mgLat = wgLat + dLat;
        mgLon = wgLon + dLon;
        return [mgLon, mgLat];
    },
    /**
     * 墨卡托坐标转纬度函数
     * @param {Number} x 横坐标
     * @param {Number} y 纵坐标
     * @return {Number} 纬度
     */
    transformLat: function(x, y) {
        var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0;
        return ret;
    },
    /**
     * 墨卡托坐标转经度函数
     * @param {Number} x 横坐标
     * @param {Number} y 纵坐标
     * @return {Number} 经度
     */
    transformLon: function(x, y) {
        var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0;
        return ret;
    },

cookie\存储操作

获取cookie

// 获取cookie
export function getCookie(cname) {
    var name = cname + '='
    var decodedCookie = decodeURIComponent(document.cookie)
    var ca = decodedCookie.split(';')
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i]
        while (c.charAt(0) === ' ') {
            c = c.substring(1)
        }
        if (c.indexOf(name) === 0) {
            return c.substring(name.length, c.length)
        }
    }
    return ''
}

存储loalStorage

export const loalStorageSet = (key, value) => {
    if (!key) return;
    if (typeof value !== 'string') {
        value = JSON.stringify(value);
    }
    window.localStorage.setItem(key, value);
};

时间操作

时长转换单位

/**
* @description:  时长转换单位
* @param: preUnit,afterUnit =>moment时长单位 seconds,minutes,hours,days,weeks,months,years
* @author: Waker
*/
export function durationUnitChange(time, preUnit, afterUnit) {
  const map = {
    years: '年',
    months: '月',
    days: '日',
    hours: '时',
    minutes: '分',
    seconds: '秒'
  }
  const momentDuration = moment.duration(time, preUnit)._data
  let formatTime = '';
  for (const key in map) {
    const unit = map[key];
    const time = momentDuration[key];
    if (time > 0) {
      formatTime = formatTime + time + unit
    }
  }

  return formatTime
}

获取下个制定周几的日期

/**
* @description:  计算下个入职日期
* @param: 每周二、四是入职日
* @author: Waker
  @use: joinDay('2021-02-27')
*/
function joinDay(date?: any) {
  // 获取日期是星期几
  const week = computedWeekDay({ date: date })
  const weekDate: any = {
    1: computedWeekDay({ date, weekDay: 2 }),
    2: computedWeekDay({ date, weekDay: 4 }),
    3: computedWeekDay({ date, weekDay: 4 }),
    4: computedWeekDay({ date, weekDay: 9 }),
    5: computedWeekDay({ date, weekDay: 9 }), //2+7 9为下个星期2
    6: computedWeekDay({ date, weekDay: 9 }),
    7: computedWeekDay({ date, weekDay: 9 }),
  }
  console.log(weekDate[week]);
  return weekDate[week]
}

设置|获取日期的周几

/**
* @description:  设置|获取日期的周几
* @param: date:日期(空为当天),weekDay:日期当前周的星期几
* @author: Waker
*/
function computedWeekDay({ date, weekDay }: any) {
  // 有weekDay表示想获取日期的所在周的某天日期
  if (weekDay) {
    return moment(date).day(weekDay).format('YYYY-MM-DD')
  }
  return moment(date).day()
}

当前时间

export const nowTime = () => {
    const now = new Date();
    const year = now.getFullYear();
    const month = now.getMonth();
    const date = now.getDate() >= 10 ? now.getDate() : ('0' + now.getDate());
    const hour = now.getHours() >= 10 ? now.getHours() : ('0' + now.getHours());
    const miu = now.getMinutes() >= 10 ? now.getMinutes() : ('0' + now.getMinutes());
    const sec = now.getSeconds() >= 10 ? now.getSeconds() : ('0' + now.getSeconds());
    return +year + "年" + (month + 1) + "月" + date + "日 " + hour + ":" + miu + ":" + sec;
}

格式化时间

export const dateFormater = (formater, time) => {
    let date = time ? new Date(time) : new Date(),
        Y = date.getFullYear() + '',
        M = date.getMonth() + 1,
        D = date.getDate(),
        H = date.getHours(),
        m = date.getMinutes(),
        s = date.getSeconds();
    return formater.replace(/YYYY|yyyy/g, Y)
        .replace(/YY|yy/g, Y.substr(2, 2))
        .replace(/MM/g,(M<10 ? '0' : '') + M)
        .replace(/DD/g,(D<10 ? '0' : '') + D)
        .replace(/HH|hh/g,(H<10 ? '0' : '') + H)
        .replace(/mm/g,(m<10 ? '0' : '') + m)
        .replace(/ss/g,(s<10 ? '0' : '') + s)
}
// dateFormater('YYYY-MM-DD HH:mm:ss')
// dateFormater('YYYYMMDDHHmmss')

时间段重合

/**
 * 判断是否有重叠的日期区间 如果想确定时间区间请在传来的数据前加上一个固定日期如'1970-01-01 00:00' -- wangwei
 * @param timeList 日期区域
 * @param mateTimeArr 匹配日期区域集合
 */
export function isTimeOver(timeList: any[], timeArr: any[], type = 'day') {
    if (!timeArr || timeArr.length === 0) {
        return false
    }

    if (type === 'time') {
        timeList = timeList.map((item) => {
            return moment(item, 'HH:mm')
        })

        timeArr = timeArr.map(item => {
            return [moment(item[0], 'HH:mm'), moment(item[1], 'HH:mm')]
        });
    }

    for (let i = 0; i < timeArr.length; i++) {
        const item = timeArr[i];

        if (moment(timeList[0]).isBetween(item[0], item[1]) || moment(timeList[1]).isBetween(item[0], item[1])) {
            return true
        } else {
            // 在匹配的左边 或者 右边
            if (!(moment(timeList[0]).isSameOrBefore(item[0]) && moment(timeList[1]).isSameOrBefore(item[0])) &&
                !(moment(timeList[0]).isSameOrAfter(item[1]) && moment(timeList[1]).isSameOrAfter(item[1]))) {
                return true
            }
        }
    }
}

数据/值操作

数组操作

数组乱序

export const arrScrambling = (arr) => {
    for (let i = 0; i < arr.length; i++) {
      const randomIndex = Math.round(Math.random() * (arr.length - 1 - i)) + i;
      [arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]];
    }
    return arr;
}

扁平化数组

/**
* @description: 扁平化数组
* @param: value:值
* @author: Waker
*/
function flatArray(array: any[], childrenKey = "children", _level = 0) {
  _level = _level + 1
  return array.reduce((total: any[], item: any) => {
    total.push({
      ...item,
      _level,
    })
    // 是否有子菜单,并递归处理
    if (item[childrenKey]?.length > 0) {
      total.push(...flatArray(item[childrenKey], childrenKey, _level))
    }
    return total
  }, [])
}

扁平化树=>匹配option的字段

/**
* @description:  根据option扁平化树
* @param: data:array=数据,childrenKey=子节点的key,option:string[]=需要导出的字段集合
* @author: Waker
*/
function flatArrayToOption({ data, childrenKey = "children", options }: any) {
  return data.reduce((total: any[], item: any) => {
    const it: any = {}
    options.forEach((key: any) => {
      it[key] = item[key]
    });
    total.push(it)
    // 是否有子菜单,并递归处理
    if (item[childrenKey]?.length > 0) {
      total.push(...flatArrayToOption({ data: item[childrenKey], options }))
    }
    return total
  }, [])
}

将树的某个key组成数组取出,可过滤

/**
* @description:  将树的某个key组成数组取出
* @param: data:array=数据,childrenKey=子节点的key,key:string=需要取出的key,filterMethod:Boolean = 过滤方法,返回假值会过滤掉
* @author: Waker
*/
function flatArrayToKey({ data, childrenKey = "children", key, filterMethod }: any) {
  return data.reduce((total: any[], item: any) => {
    // 是否有过滤条件
    if (filterMethod) {
      if (typeof (filterMethod) !== 'function') {
        throw 'filterMethod必须是个函数'
      }
      const isOK = filterMethod(item)
      if (isOK) {
        total.push(item[key])
      }
    } else {
      total.push(item[key])
    }
    // 是否有子菜单,并递归处理
    if (item[childrenKey]?.length > 0) {
      total.push(...flatArrayToKey({ data: item[childrenKey], key, filterMethod }))
    }
    return total
  }, [])
}

对象操作

import { isEmpty, get } from 'lodash';
/**
* @description: 路径取值: 空值、空对象、空集合,空映射或者set 返回默认值
* @param: ob:对象,路径:在ob内的路径,例子:'a[0].b.c',defaultVal:默认值    
* @author: Waker
*/
function readProp(ob: any, path: string, defaultVal: any = '') {
  const value = get(ob, path);
  return emptyDefault(value, defaultVal)
}

/**
* @description: 空值默认 : 空值、空对象、空集合,空映射或者set 返回默认值
* @param: value:值,defaultVal:默认值
* @author: Waker
*/
function emptyDefault(value: any, defaultVal: any = '') {
  // 空值
  if (!value && value !== 0) return defaultVal;
  // 空对象、空集合,空映射或者set
  if (value instanceof Object && isEmpty(value)) return defaultVal;
  return value
}

字符串操作

字符串首字母大写

export const fistLetterUpper = (str) => {
    return str.charAt(0).toUpperCase() + str.slice(1);
};

驼峰命名转换成短横线命名

export const getKebabCase = (str) => {
    return str.replace(/[A-Z]/g, (item) => '-' + item.toLowerCase())
}

短横线命名转换成驼峰命名

export const getCamelCase = (str) => {
    return str.replace( /-([a-z])/g, (i, item) => item.toUpperCase())
}

全角转换为半角

export const toCDB = (str) => {
  let result = "";
  for (let i = 0; i < str.length; i++) {
    code = str.charCodeAt(i);
    if (code >= 65281 && code <= 65374) {
      result += String.fromCharCode(str.charCodeAt(i) - 65248);
    } else if (code == 12288) {
      result += String.fromCharCode(str.charCodeAt(i) - 12288 + 32);
    } else {
      result += str.charAt(i);
    }
  }
  return result;
}

半角转换为全角

export const toDBC = (str) => {
  let result = "";
  for (let i = 0; i < str.length; i++) {
    code = str.charCodeAt(i);
    if (code >= 33 && code <= 126) {
      result += String.fromCharCode(str.charCodeAt(i) + 65248);
    } else if (code == 32) {
      result += String.fromCharCode(str.charCodeAt(i) + 12288 - 32);
    } else {
      result += str.charAt(i);
    }
  }
  return result;
}

随机数生成

export const randomNum = (start, end, dec = 2) => +(start + (Math.random() * (end - start))).toFixed(dec);

图片

/**
* @description: 校验图片尺寸
* @param: 
* @author: Waker
*/

function validateImageSize({ file, width, height }: any) {
  if (!file|| !height || !width) {
    console.error('校验图片尺寸时,文件、宽、高必填');
    return file;
  }
  return new Promise(function (resolve, reject) {
    const _URL = window.URL || window.webkitURL;
    const image = new Image();
    image.onload = function () {
      const valid = image.width == width && image.height == height;
      valid ? resolve(valid) : reject();
    };
    image.src = _URL.createObjectURL(file);
  })
    .then(() => {
      return file;
    })
    .catch(() => {
      return Promise.reject(`上传图片尺寸必须为800*800`);
    });
}

数组操作

vue专属

跳转锚点与路由冲突

/**
* @description: 跳转锚点与路由冲突
* @param: 
* @author: Waker
*/
skipModel(id: string) {
  const dom: any = document.querySelector("#" + id);
  dom.scrollIntoView({ behavior: "smooth" });
}

react专属