前端项目常用工具类

在lib目录下新建util.js文件,里面存放项目中常用的工具类:

import { Enumify } from 'enumify'
import JSEncrypt from 'jsencrypt'

// 生成一个随机id
function newRandomId () {
  let randomId = ''
  for (let i = 1; i <= 32; i++) {
    const n = Math.floor(Math.random() * 16.0).toString(16)
    randomId += n
    if (i === 8 || i === 12 || i === 16 || i === 20) {
      randomId += '-'
    }
  }
  return randomId
}

/**
 * 函数防抖
 * @param func 需要防抖的实际方法
 * @param wait 延迟执行毫秒数
 * @param immediate true 表立即执行,false 表非立即执行
 */
function debounce (func, wait, immediate) {
  let timeout
  return function () {
    const that = this
    const args = arguments

    if (timeout) clearTimeout(timeout)
    if (immediate) {
      const callNow = !timeout
      timeout = setTimeout(function () {
        timeout = null
      }, wait)
      if (callNow) func.apply(that, args)
    } else {
      timeout = setTimeout(function () {
        func.apply(that, args)
      }, wait)
    }
  }
}

/**
 * 函数节流
 * @param func 需要节流的实际方法
 * @param wait 延迟执行毫秒数(需要控制的时间长度)
 * @param type 1 表时间戳版,2 表定时器版
 */
function throttle (func, wait, type) {
  if (type === 1) {
    const previous = 0 // 第一次执行的时候是0,第一次点击的时候肯定大于这个数,所以会立马执行
  } else if (type === 2) {
    let timeout
  }
  return function () {
    const that = this
    const args = arguments
    if (type === 1) {
      const now = Date.now() // 实际执行的时间

      if (now - previous > wait) {
        // 执行的时间是不是比上次执行的时间大于需要延迟的时间,大于,则执行
        func.apply(that, args)
        previous = now // 执行了以后,重置上一次执行的时间为刚刚执行这次函数的时间,下次执行就用这个时间为基准
      }
    } else if (type === 2) {
      if (!timeout) {
        timeout = setTimeout(function () {
          timeout = null
          func.apply(that, args)
        }, wait)
      }
    }
  }
}

/**
 * 冻结对象的属性 防止篡改
 * @param {对象} TargetObj
 * @returns
 */
function getEnum (TargetObj) {
  if (TargetObj instanceof Function) {
    const enumInstance = new TargetObj()
    if (!(enumInstance instanceof Enumify)) {
      throw new Error('类型不对')
    }
    freezeObj(TargetObj)
    return TargetObj
  } else if (typeof EnumObj === 'object') {
    freezeObj(TargetObj)
    return TargetObj
  }
}

/**
 * 一层层冻结目标对象
 * @param { Object } targetObj
 */
function freezeObj (targetObj) {
  if (
    !['object', 'function'].includes(typeof targetObj) ||
    targetObj === null
  ) {
    return
  }
  let i
  for (i in targetObj) {
    // 判断当前复制的对象是否为对象类型数据
    if (typeof targetObj[i] === 'object') {
      Object.freeze(targetObj[i])
    }
  }
}

/**
 * 获取路径上的参数对象
 * @returns {Object}
 */
function getCurrentRouteQuery () {
  const query = {}
  const search =
    location.href.split('?').length > 1 && location.href.split('?')[1] // url参数
  const urlParams = search && search.split('&') // url参数数组
  if (urlParams && urlParams.length) {
    urlParams.forEach((item) => {
      const list = item.split('=')
      query[list[0]] = list[1] ? decodeURI(list[1]) : ''
    })
  }
  return query
}

/**
 * 下载
 */
function saveBlobToFile (res, fileName) {
  const regFilename = /filename=([^;]+)/i
  if (res.headers['content-disposition']) {
    // 从header获取并转化
    const resFileName = decodeURIComponent(
      res.headers['content-disposition'].match(regFilename)[1]
    )
    const blob = res.data

    if (navigator.msSaveBlob) {
      navigator.msSaveBlob(blob, resFileName)
    } else {
      const oA = document.createElement('a')
      try {
        oA.href = URL.createObjectURL(blob)
      } catch (err) {
        const binaryData = []
        binaryData.push(blob)
        oA.href = window.URL.createObjectURL(
          new Blob(binaryData, { type: 'application/zip' })
        )
      }
      oA.download = fileName || resFileName
      oA.click()
    }
  }
}

/**
 * 暂停进程(模拟)
 * @param {any} time
 * @returns {any}
 */
async function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time))
}

/**
 * 等待并执行 定时间检查是否满足allow条件 当允许时 执行func
 * @param {function} allow 满足等待的条件
 * @param {function} func
 * @param {number} time=200
 */
async function waitToRun (allow, func, time = 200) {
  if (!allow()) {
    await sleep(time)
    return waitToRun(allow, func, time)
  } else {
    return func()
  }
}

// # utils of tree
/**
 * 树 遍历访问器
 * @param {any} tree
 * @param {any} callback
 * @returns {any}
 */
function forEachTreeNode (tree, callback) {
  if (!tree && typeof tree !== 'object') return

  const loop = (treeArr = [], parent, allAncestors) => {
    treeArr.forEach((item, idx, children) => {
      callback(item, idx, children, parent, allAncestors)
      if (item.children) {
        loop(item.children, item, [...allAncestors, item])
      }
    })
  }
  // 数组 or 对象
  // eslint-disable-next-line no-unused-expressions
  tree.length
    ? loop(tree, null, [])
    : (callback(tree, null, null, null), loop(tree.children, tree, []))
}

/**
 * 获取 vm.$route.query
 * 并 将值全部转换为 字符串形式 避免数字类型的值刷新后成为字符串 造成判断错误
 * eg. routeQuey.call(this)
 * @param initialObj 初始对象 在此基础上赋值
 * @returns {any}
 */
function getRouteQuery (initialObj) {
  const { query } = this.$route // 路由
  return Object.keys(query).reduce(
    (acc, cur) => ({
      ...acc,
      [cur]: query[cur] + ''
    }),
    initialObj
  )
}

/**
 * form 重置校验 未传则重置全部 需要绑定 this 为当前vue实例
 * @param {any} propArr 需要重置的prop数组
 * @returns {any}
 */
function resetFormValidates (propArr = []) {
  this.$nextTick(() => {
    if (!this.$refs.formRef) return
    const formRef = this.$refs.formRef.elRef || this.$refs.formRef

    propArr.length
      ? propArr.forEach((prop) => formRef.resetValidate(prop))
      : formRef.resetValidates()
  })
}

/**
 * setTimeout 短轮询
 * @param func 被执行的请求promise函数 返回的结果bol会作为是否中断轮询的标识
 * @param wait 执行时间间隔
 * @param limit 最大请求次数 超过限制则会强制结束 默认20次
 * @param count 递归用 请求次数 从1开始
 * @param callback 回调
 * @param count 请求次数
 * @param isEnd 是否结束
 */
function polling (func, { wait, limit = 20, count = 1 }, callback) {
  if (!func) return
  const str = Object.prototype.toString.call(func)
  // 获取中断标志的函数
  const getBreakFlag = async () => {
    if (str.includes('AsyncFunction') || str.includes('Promise')) {
      const res = await func()
      return res
    } else {
      return func()
    }
  }

  setTimeout(async () => {
    const breakFlag = await getBreakFlag()

    if (count >= limit || breakFlag) {
      callback && callback(count, true)
      clearTimeout(polling)
    } else {
      callback && callback(count, false)
      polling(func, { wait, limit, count: ++count }, callback)
    }
  }, wait)
}

/**
 * 深度assign两个对象( 非对象类型将取后面的值 )
 */
export const deepAssign = (srcObj, mergedFromObj) => {
  const isObject = (tar) =>
    Object.prototype.toString.call(tar).includes('Object')
  const isArray = (tar) => Object.prototype.toString.call(tar).includes('Array')

  // 支持深层次链式调用 防止报错
  const optionalChaining = (obj, ...rest) => {
    let temp = obj
    for (const key of rest) {
      if (temp === undefined) return undefined
      temp = (temp || {})[key]
    }
    return temp
  }

  const loop = (obj, path = []) => {
    const cache = {}
    for (const key in obj) {
      const curPath = [...path, key]

      if (isObject(obj[key])) {
        cache[key] = loop(obj[key], curPath)
      } else if (isArray(obj[key])) {
        cache[key] = Object.values(loop(obj[key], curPath))
      } else {
        const mergedVal = optionalChaining(mergedFromObj, ...curPath)
        cache[key] =
          mergedVal !== undefined && typeof mergedVal !== 'object'
            ? mergedVal
            : obj[key]
      }
    }
    return cache
  }

  return loop(srcObj)
}

// 获取显示时间范围
function getPastTime (month) {
  const time = new Date()
  const yy = time.getFullYear() // 获取完整的年份(4位,1970-???)
  const M = time.getMonth() + 1 // 获取当前月份(0-11,0代表1月),
  const d = time.getDate() // 获取当前日(1-31)
  const H = time.getHours() // 获取当前小时数(0-23)
  const m = time.getMinutes() // 获取当前分钟数(0-59)
  const s = time.getSeconds() // 获取当前秒数(0-59)
  // 获取指定的过去时间
  const past = M - month
  const pastM = past <= 0 ? (past + 12 + '') : past > 9 ? (past + '') : '0' + past
  // 小于9的,在前面加0
  const MM = M > 9 ? M : '0' + M
  const dd = d > 9 ? d : '0' + d
  const HH = H > 9 ? H : '0' + H
  const mm = m > 9 ? m : '0' + m
  const ss = s > 9 ? s : '0' + s
  // 指定的过去时间
  const pastY = past <= 0 ? yy - 1 : yy
  let pastD = dd
  if (pastM === '02' && pastD > 28) { // 判断是否为闰年
    pastD = ((pastY % 4 === 0 && pastY % 100 !== 0) || pastY % 400 === 0) ? 29 : 28
  } else if ((pastM === '04' || pastM === '06' || pastM === '09' || pastM === '11') && pastD === 31) {
    pastD = 30
  }
  const PastTime = pastY + '-' + pastM + '-' + pastD + ' ' + HH + ':' + mm + ':' + ss
  // 当前时间
  const nowTime = yy + '-' + MM + '-' + dd + ' ' + HH + ':' + mm + ':' + ss

  return [PastTime, nowTime]
}

function pickerOptionsRelative () {
  const shortcuts = [
    {
      text: '今日',
      onClick (picker) {
        const start = new Date()
        start.setHours(0, 0, 0, 0)
        const end = new Date()
        end.setHours(23, 59, 59, 0)
        picker.$emit('pick', [start, end], true)
      }
    },
    {
      text: '昨日',
      onClick (picker) {
        const start = new Date()
        start.setTime(start.getTime() - 3600 * 1000 * 24)
        start.setHours(0, 0, 0, 0)
        const end = new Date()
        end.setTime(end.getTime() - 3600 * 1000 * 24)
        end.setHours(23, 59, 59, 0)
        picker.$emit('pick', [start, end], true)
      }
    },
    {
      text: '本周',
      onClick (picker) {
        const end = new Date()
        const start = new Date()
        // 现在星期几;0代表星期天,6代表星期六
        const thisDay = start.getDay() || 7
        start.setTime(start.getTime() - 3600 * 1000 * 24 * (thisDay - 1))
        end.setTime(end.getTime() + 3600 * 1000 * 24 * (7 - thisDay))
        start.setHours(0, 0, 0, 0)
        end.setHours(23, 59, 59, 0)
        picker.$emit('pick', [start, end], true)
      }
    },
    {
      text: '上周',
      onClick (picker) {
        // 上周开始时间
        const starta = new Date()
        const first = starta.getDate() - starta.getDay() - 6
        const startDate = new Date(starta.setDate(first))
        const start = new Date(startDate)
        start.setHours(0, 0, 0, 0)
        //  上周结束时间
        const currentDate = new Date()
        const firsts = currentDate.getDate() - currentDate.getDay() - 6
        const last = firsts + 6
        const endDate = new Date(currentDate.setDate(last))
        const end = new Date(endDate)
        end.setHours(23, 59, 59, 0)
        picker.$emit('pick', [start, end], true)
      }
    },
    {
      text: '本月',
      onClick (picker) {
        const currentDate = new Date()
        const end = new Date()
        const start = new Date()
        // end.setTime(start.getTime() - 3600 * 1000 * 24)
        start.setDate(1)
        // 获取当前月天数
        const currentMonth = new Date(
          currentDate.getFullYear(),
          currentDate.getMonth() + 1,
          0
        )
        const currentMonthDay = currentMonth.getDate()
        end.setDate(currentMonthDay)
        start.setHours(0, 0, 0, 0)
        end.setHours(23, 59, 59, 0)
        picker.$emit('pick', [start, end], true)
      }
    },
    {
      text: '上月',
      onClick (picker) {
        // 获取当前时间
        const currentDate = new Date()
        // 获得当前月份0-11
        let currentMonth = currentDate.getMonth()
        // 获得当前年份4位年
        let currentYear = currentDate.getFullYear()
        // 获得上一个月的第一天
        if (currentMonth === 0) {
          currentMonth = 11 // 月份为上年的最后月份
          currentYear-- // 年份减1
          return new Date(currentYear, currentMonth, 1)
        } else {
          // 否则,只减去月份
          currentMonth--
        }
        const start = new Date(currentYear, currentMonth, 1)
        // 获取当前时间
        const currentDates = new Date()
        // 获得当前月份0-11
        let currentMonths = currentDates.getMonth()
        // 获得当前年份4位年
        // let currentYears = currentDates.getFullYear()
        // 当为12月的时候年份需要加1
        // 月份需要更新为0 也就是下一年的第一个月
        if (currentMonths === 11) {
          // currentYears++
          currentMonths = 0
        } else {
          // 否则只是月份增加,以便求的下一月的第一天
          currentMonths++
        }
        // 一天的毫秒数
        const millisecond = 1000 * 60 * 60 * 24
        // 求出上月的最后一天
        const aa = new Date()
        const thisMonth = aa.getMonth()
        // 获得当前年份4位年
        const thisYear = aa.getFullYear()
        // 求出本月第一天
        const firstDay = new Date(thisYear, thisMonth, 1)
        const lastDay = new Date(firstDay.getTime() - millisecond)
        const end = new Date(lastDay)
        start.setHours(0, 0, 0, 0)
        end.setHours(23, 59, 59, 0)
        picker.$emit('pick', [start, end], true)
      }
    },
    // {
    //   text: '本季度',
    //   onClick (picker) {
    //     var oDate = new Date()
    //     var thisYear = oDate.getFullYear()
    //     var thisMonth = oDate.getMonth() + 1
    //     var n = Math.ceil(thisMonth / 3) // 季度
    //     var Month = n * 3 - 1
    //     var start = new Date(thisYear, Month - 2, 1)
    //     var end = new Date()
    //     end.setTime(end.getTime() - 3600 * 1000 * 24)
    //     picker.$emit('pick', [start, end])
    //   },
    // },
    {
      text: '本年',
      onClick (picker) {
        const end = new Date()
        const start = new Date()
        start.setMonth(0)
        start.setDate(1)
        end.setMonth(11)
        end.setDate(31)
        start.setHours(0, 0, 0, 0)
        end.setHours(23, 59, 59, 0)
        // end.setTime(end.getTime() - 3600 * 1000 * 24)
        picker.$emit('pick', [start, end], true)
      }
    },
    {
      text: '上年',
      onClick (picker) {
        // 获取当前时间
        const currentDate = new Date()
        // 获得当前年份4位年
        const currentYear = currentDate.getFullYear() - 1
        // 本年第一天
        const start = new Date(currentYear, 0, 1)
        // 本年最后一天
        const end = new Date(currentYear, 11, 31)
        start.setHours(0, 0, 0, 0)
        end.setHours(23, 59, 59, 0)
        picker.$emit('pick', [start, end], true)
      }
    },
    {
      text: '过去七天', // 近一周
      onClick (picker) {
        const end = new Date()
        const start = new Date()
        end.setTime(start.getTime() - 3600 * 1000 * 24)
        start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
        start.setHours(0, 0, 0, 0)
        end.setHours(23, 59, 59, 0)
        picker.$emit('pick', [start, end], true)
      }
    },
    {
      text: '过去30天', // 近一月
      onClick (picker) {
        const end = new Date()
        const start = new Date()
        end.setTime(start.getTime() - 3600 * 1000 * 24)
        start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
        start.setHours(0, 0, 0, 0)
        end.setHours(23, 59, 59, 0)
        picker.$emit('pick', [start, end], true)
      }
    },
    {
      text: '过去90天', // 近三月
      onClick (picker) {
        const end = new Date()
        const start = new Date()
        end.setTime(start.getTime() - 3600 * 1000 * 24)
        start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
        start.setHours(0, 0, 0, 0)
        end.setHours(23, 59, 59, 0)
        picker.$emit('pick', [start, end], true)
      }
    },
    {
      text: '过去180天', // 近半年
      onClick (picker) {
        const end = new Date()
        const start = new Date()
        end.setTime(start.getTime() - 3600 * 1000 * 24)
        start.setTime(start.getTime() - 3600 * 1000 * 24 * 180)
        start.setHours(0, 0, 0, 0)
        end.setHours(23, 59, 59, 0)
        picker.$emit('pick', [start, end], true)
      }
    }
    // {
    //   text: '近一年',
    //   onClick (picker) {
    //     const end = new Date()
    //     const start = new Date()
    //     end.setTime(start.getTime() - 3600 * 1000 * 24)
    //     start.setTime(start.getTime() - 3600 * 1000 * 24 * 365)
    //     picker.$emit('pick', [start, end])
    //   },
    // },
    // {
    //   text: '自定义',
    //   type: '1',
    //   onClick (picker) {
    //     const end = new Date()
    //     const start = new Date()
    //     end.setTime(start.getTime() - 3600 * 1000 * 24)
    //     start.setTime(start.getTime() - 3600 * 1000 * 24 * 180)
    //     picker.$emit('pick', [start, end], true)
    //   },
    // },
  ]
  return { shortcuts }
}
function getBreadCrumb (bread) {
  // 如果不是单机版,全部配置全部改为高级配置
  try {
    if (window.top.createBreadList && window.top.createBreadList() && window.top.createBreadList().length) {
      return window.top.createBreadList()
    } else {
      return bread
    }
  } catch (error) {
    return bread
  }
}
// 格式化日期
function formatDate (timeDate, fmt) {
  if (timeDate) {
    let time = null
    if (typeof timeDate === 'object') {
      time = timeDate
    } else {
      time = new Date(timeDate)
      if (time instanceof Date && isNaN(time.getTime())) {
        // 不是合法日期格式,则为ie,需要做时间转换
        if (timeDate.split('.')[1]) { timeDate = timeDate.split('.')[0] + '+' + timeDate.split('.')[1].split('+')[1] }

        time = new Date(timeDate.replace(/-/g, '/'))
      }
    }

    if (!fmt) fmt = 'yyyy-MM-dd hh:mm:ss.S'
    const o = {
      'M+': time.getMonth() + 1, // 月份
      'd+': time.getDate(), // 日
      'h+': time.getHours(), // 小时
      'm+': time.getMinutes(), // 分
      's+': time.getSeconds(), // 秒
      'q+': Math.floor((time.getMonth() + 3) / 3), // 季度
      S: time.getMilliseconds() // 毫秒
    }
    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (time.getFullYear() + '').substr(4 - RegExp.$1.length))
    for (const k in o) {
      if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
    }
    return fmt
  } else {
    return timeDate || '--'
  }
}
// 下载文件
function saveBoloToFile (blob, fileName) {
  if (navigator.msSaveBlob) {
    navigator.msSaveBlob(blob, fileName)
  } else {
    const oA = document.createElement('a')
    oA.href = URL.createObjectURL(blob)
    oA.download = fileName
    oA.click()
  }
}
/**
   * @Desc: post方式打开新窗口
   */
function openPostWindow (url, name, obj) {
  const tempForm = document.createElement('form')

  tempForm.id = 'tempForm1'
  tempForm.method = 'get'
  tempForm.action = url
  tempForm.target = '_self'

  for (const p in obj) {
    const hideInput = document.createElement('input')
    hideInput.type = 'hidden'
    hideInput.name = p
    hideInput.value = obj[p]
    tempForm.appendChild(hideInput)
  }

  if (window.addEventListener) {
    tempForm.addEventListener('onsubmit', function () { openWindow(name) })
  } else if (window.attachEvent) {
    tempForm.attachEvent('onsubmit', function () { openWindow(name) })
  }
  document.body.appendChild(tempForm)

  tempForm.submit()
  document.body.removeChild(tempForm)
}
function openWindow (name) {
  window.open('about:blank', name, 'height=400, width=400, top=0, left=0, toolbar=yes, menubar=yes, scrollbars=yes, resizable=yes,location=yes, status=yes')
}

// 格式化数字
function formatData (n) {
  if (!n || isNaN(n)) return
  const b = parseInt(n).toString()
  const len = b.length
  if (len <= 3) { return b }
  const r = len % 3
  return r > 0 ? b.slice(0, r) + ',' + b.slice(r, len).match(/\d{3}/g).join(',') : b.slice(r, len).match(/\d{3}/g).join(',')
}
function setEncryptLong2 () {
  // 扩展加解密方法
  const b64map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  const b64pad = '='
  function hex2b64 (h) {
    let i
    let c
    let ret = ''
    for (i = 0; i + 3 <= h.length; i += 3) {
      c = parseInt(h.substring(i, i + 3), 16)
      ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63)
    }
    if (i + 1 === h.length) {
      c = parseInt(h.substring(i, i + 1), 16)
      ret += b64map.charAt(c << 2)
    } else if (i + 2 === h.length) {
      c = parseInt(h.substring(i, i + 2), 16)
      ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4)
    }
    while ((ret.length & 3) > 0) {
      ret += b64pad
    }
    return ret
  }
  JSEncrypt.prototype.encryptLong2 = function (string) {
    const k = this.getKey()
    try {
      let ct = ''
      // RSA每次加密117bytes,需要辅助方法判断字符串截取位置
      // 1.获取字符串截取点
      const bytes = []
      bytes.push(0)
      let byteNo = 0
      let c
      const len = string.length
      let temp = 0
      for (let i = 0; i < len; i++) {
        c = string.charCodeAt(i)
        if (c >= 0x010000 && c <= 0x10FFFF) {
          byteNo += 4
        } else if (c >= 0x000800 && c <= 0x00FFFF) {
          byteNo += 3
        } else if (c >= 0x000080 && c <= 0x0007FF) {
          byteNo += 2
        } else {
          byteNo += 1
        }
        if ((byteNo % 245) >= 242 || (byteNo % 245) === 0) {
          if (byteNo - temp >= 114) {
            bytes.push(i)
            temp = byteNo
          }
        }
      }
      // 2.截取字符串并分段加密
      if (bytes.length > 1) {
        for (let j = 0; j < bytes.length - 1; j++) {
          let str
          if (j === 0) {
            str = string.substring(0, bytes[j + 1] + 1)
          } else {
            str = string.substring(bytes[j] + 1, bytes[j + 1] + 1)
          }
          const t1 = k.encrypt(str)
          ct += t1
        }
        ;
        if (bytes[bytes.length - 1] !== string.length - 1) {
          const lastStr = string.substring(bytes[bytes.length - 1] + 1)
          ct += k.encrypt(lastStr)
        }
        return hex2b64(ct)
      }
      const t = k.encrypt(string)
      const y = hex2b64(t)

      return y
    } catch (ex) {
      return false
    }
  }
}
function removeFailList (list, value) {
  if (!list) return
  const index = list.indexOf(value)
  if (index >= 0) {
    list.splice(index, 1)
  }
}

/**
 * @func generateUppercaseLetterList
 * @desc 获取26个大写英文字母的数组
 * @return []
 */
function generateUppercaseLetterList () {
  const CHARCODE_A_UC = 65
  const uppercaseAlphabet = new Array(26).fill(null).map((v, i) => String.fromCharCode(CHARCODE_A_UC + i))
  return uppercaseAlphabet
}
/**
 * 数字串加逗号分隔
 */
function splitForComma (num) {
  if (!num) return 0
  const arr = num.toString().split('').reverse()
  const resArr = []
  arr.forEach((item, index) => {
    resArr.push(item)
    if ((index + 1) % 3 === 0 && index !== arr.length - 1) resArr.push(',')
  })
  return resArr.reverse().join('')
}

let deepCopy = (targetObj) => {
  // 若不是对象类型或是null类型,直接输出
  if (typeof targetObj !== 'object' || targetObj === null) {
    return targetObj
  }
  let i
  // 根据目标是Array类型还是object来设置目标参数的类型
  let target = Array.isArray(targetObj) ? [] : {}
  for (i in targetObj) {
    // 判断当前复制的对象是否为对象类型数据
    if (typeof targetObj[i] === 'object') {
      target[i] = deepCopy(targetObj[i])
    } else {
      target[i] = targetObj[i]
    }
  }
  return target
}

/**
 * 根据容器获取容器里面的html字符串  把css样式转换为内联样式  以便生成可直接离线访问的html文档或者svg文件
 * @param {Document} svgContent
 * @returns
 */
function getEleStrFormSvg (svgContent) {
  if (!svgContent) {
    return ''
  }
  const svgContainer = svgContent.tagName === 'svg' ? svgContent : svgContent.querySelector('svg')
  if (!svgContainer) {
    return ''
  }
  const contentDom = svgContainer.cloneNode(true)

  const svgChildren = contentDom.querySelectorAll('svg')
  for (const svg of svgChildren) {
    if (svg === contentDom) continue
    const parent = svg.parentNode
    const imgDom = getImgReplaceSvg(svg)
    parent.replaceChild(imgDom, svg)
  }

  const sheets = document.styleSheets
  const sheetsArry = Array.from(sheets)
  sheetsArry.forEach(sheetContent => {
    console.log('sheetContent==', sheetContent)
    const { rules, cssRules } = sheetContent
    // cssRules兼容火狐
    const rulesArry = Array.from(rules || cssRules || [])
    rulesArry.forEach(rule => {
      const { selectorText, style } = rule
      // 全局样式不处理
      if (selectorText !== '*') {
      // 兼容某些样式在转换的时候会报错
        try {
          const select = contentDom.querySelectorAll(selectorText)
          const origin = svgContent.querySelectorAll(selectorText)
          Array.from(select).forEach((dom, index) => {
            let i = 0
            const domStyle = window.getComputedStyle(origin[index], null)
            while (style[i]) {
            // 式表里的className是驼峰式,转换下便对应上了
              const newName = style[i].replace(/-\w/g, function (x) {
                return x.slice(1).toUpperCase()
              })
              dom.style[style[i]] = domStyle[newName]
              i++
            }
          })
        } catch (e) {
          console.log('转换成行内样式失败')
        }
      }
    })
  })
  return contentDom.outerHTML
}
function getImgReplaceSvg (svgNode) {
  const dom = document.createElement('img')
  dom.style.width = 32 + 'px'
  dom.style.height = 32 + 'px'
  let svg = svgNode.outerHTML.trim()
  let canvas = document.createElement('canvas')
  canvas.width = svgNode.getBoundingClientRect().width
  canvas.height = svgNode.getBoundingClientRect().height
  canvg(canvas, svg)
  dom.src = canvas.toDataURL('image/png')
  return dom
}

// 进行正则表达式转义编码
function encodeRegExp (keyword) {
  const reg = /[[($^.\]*\\?+{}|)]/gi
  return keyword.replace(reg, (key) => `\\${key}`)
}

/**
 * 获取以千分隔的数字
 * @param num 数字
 */
function getThousandSplitNum (num, isNumber = false) {
  if (!isNumber && (typeof num !== 'number' || !num)) {
    return num
  }
  let minusSymbol = '' // 负数标志
  if (num < 0) {
    num = -num
    minusSymbol = '-'
  }
  let numStr = num.toString()
  let [intStr, floatStr] = numStr.split('.')
  if (intStr.length < 3) {
    return minusSymbol + numStr
  }
  const strArr = []
  for (let i = intStr.length; i > 0; i = i - 3) {
    strArr.push(intStr.substring(i - 3, i))
  }
  strArr.reverse()
  return minusSymbol + strArr.join(',') + (floatStr ? '.' + floatStr : '')
}

/**
 * findeLastIndex 兼容低版本浏览器
 * @param {*} target
 */
function findArrayLastIndex (list = [], findFunc) {
  let index = -1
  if (!findFunc || typeof findFunc !== 'function') {
    return -1
  }
  const length = list.length
  for (let i = length - 1; i >= 0; i--) {
    if (findFunc(list[i], i)) {
      index = i
      break
    }
  }
  return index
}

function getActualWidthOfChars (text, options = {}) {
  const { size = 14, family = 'Microsoft YaHei' } = options
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  ctx.font = `${size}px ${family}`
  const metrics = ctx.measureText(text)
  const actual = Math.abs(metrics.actualBoundingBoxLeft) + Math.abs(metrics.actualBoundingBoxRight)
  return Math.max(metrics.width, actual)
}

export {
  splitForComma,
  generateUppercaseLetterList,
  pushToFailList,
  hasOwn,
  setEncryptLong2,
  newRandomId,
  debounce,
  throttle,
  getEnum,
  getCurrentRouteQuery,
  saveBlobToFile,
  waitToRun,
  forEachTreeNode,
  getRouteQuery,
  resetFormValidates,
  polling,
  getPastTime,
  pickerOptionsRelative,
  getBreadCrumb,
  formatDate,
  saveBoloToFile,
  openPostWindow,
  formatData,
  deepCopy,
  getEleStrFormSvg,
  encodeRegExp,
  getThousandSplitNum,
  findArrayLastIndex,
  getActualWidthOfChars
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值