Skip to content

工具函数

封装自己常用的工具函数

休眠函数

等待 1000ms 后执行

ts
export function sleep<T>(ms: number, callback?: Function) {
  return new Promise<T>((resolve, reject) =>
    setTimeout(async () => {
      try {
        const value = await callback?.()
        resolve(value)
      }
      catch (error) {
        reject(error)
      }
    }, ms),
  )
}
export function sleep<T>(ms: number, callback?: Function) {
  return new Promise<T>((resolve, reject) =>
    setTimeout(async () => {
      try {
        const value = await callback?.()
        resolve(value)
      }
      catch (error) {
        reject(error)
      }
    }, ms),
  )
}

设置 rem 基准值

设计稿的尺寸375

ts
export function setRem(screen = 375) {
  const docEl = document.documentElement

  function setBodyFontSize() {
    const scale = docEl.clientWidth / screen

    docEl.style.fontSize = `${(screen / 10) * Math.min(scale, 2)}px`
  }

  setBodyFontSize()

  window.addEventListener('resize', setBodyFontSize, false)
}
export function setRem(screen = 375) {
  const docEl = document.documentElement

  function setBodyFontSize() {
    const scale = docEl.clientWidth / screen

    docEl.style.fontSize = `${(screen / 10) * Math.min(scale, 2)}px`
  }

  setBodyFontSize()

  window.addEventListener('resize', setBodyFontSize, false)
}

经纬度计算距离

计算结果返回km单位

ts
/**
 * 根据经纬度计算距离(km)
 * @param lo1 经度
 * @param la1 维度
 * @param lo2 经度
 * @param la2 维度
 */
export function computeDistance(lo1: number, la1: number, lo2: any, la2: any) {
  const oneangle = Math.PI / 180.0
  const La1 = la1 * oneangle
  const La2 = la2 * oneangle
  const La3 = La1 - La2
  const Lb3 = lo1 * oneangle - lo2 * oneangle
  const s = 2 * Math.asin(
    Math.sqrt(
      Math.sin(La3 / 2) ** 2
      + Math.cos(La1)
      * Math.cos(La2)
      * Math.sin(Lb3 / 2) ** 2
    )
  )
  // 地球半径 6378.137 km
  return +(s * 6378.137).toFixed(4)
}
/**
 * 根据经纬度计算距离(km)
 * @param lo1 经度
 * @param la1 维度
 * @param lo2 经度
 * @param la2 维度
 */
export function computeDistance(lo1: number, la1: number, lo2: any, la2: any) {
  const oneangle = Math.PI / 180.0
  const La1 = la1 * oneangle
  const La2 = la2 * oneangle
  const La3 = La1 - La2
  const Lb3 = lo1 * oneangle - lo2 * oneangle
  const s = 2 * Math.asin(
    Math.sqrt(
      Math.sin(La3 / 2) ** 2
      + Math.cos(La1)
      * Math.cos(La2)
      * Math.sin(Lb3 / 2) ** 2
    )
  )
  // 地球半径 6378.137 km
  return +(s * 6378.137).toFixed(4)
}

下载文件

注意

Safari 手机浏览器自动添加后缀问题

ts
/**
 * 下载文件
 */
export function downloadFile(response: any) {
  const filename = response.headers['content-disposition'].split(';')[1].split('=')[1]
  // TODO Safari 手机浏览器自动添加后缀问题
  const blob = new Blob([response.data], { type: 'application/octet-stream;charset=utf-8' })

  const link = document.createElement('a')
  link.href = URL.createObjectURL(blob)
  link.setAttribute('download', decodeURI(filename))
  link.click()
  URL.revokeObjectURL(link.href)
}
/**
 * 下载文件
 */
export function downloadFile(response: any) {
  const filename = response.headers['content-disposition'].split(';')[1].split('=')[1]
  // TODO Safari 手机浏览器自动添加后缀问题
  const blob = new Blob([response.data], { type: 'application/octet-stream;charset=utf-8' })

  const link = document.createElement('a')
  link.href = URL.createObjectURL(blob)
  link.setAttribute('download', decodeURI(filename))
  link.click()
  URL.revokeObjectURL(link.href)
}

内容复制封装

兼容新API复制方案, 复制思路通过js 创建虚拟inputDOM, 调用全选功能

调用 document.execCommand('copy')进行复制

ts
/**
 * 复制功能
 * @param text 复制内容
 * @return
 */
export async function copyToClipboard(text: any) {
  try {
    // 新API 复制接口
    return await navigator.clipboard.writeText(text)
  }
  catch {
    const textRef = document.createElement('textarea')
    // 获取当前获得焦点的元素
    textRef.value = text
    // 防止键盘在手机上显示
    textRef.setAttribute('readonly', '')
    // css3 渲染限制 不在视图内不渲染
    textRef.style.contain = 'strict'
    textRef.style.position = 'absolute'
    textRef.style.left = '-9999px'
    textRef.style.fontSize = '12pt' // 防止在iOS上缩放

    document.body.appendChild(textRef)
    textRef.select()
    // iOS的选择解决方案
    textRef.selectionStart = 0
    textRef.selectionEnd = text.length
    document.execCommand('copy')
    document.body.removeChild(textRef)
  }
}
/**
 * 复制功能
 * @param text 复制内容
 * @return
 */
export async function copyToClipboard(text: any) {
  try {
    // 新API 复制接口
    return await navigator.clipboard.writeText(text)
  }
  catch {
    const textRef = document.createElement('textarea')
    // 获取当前获得焦点的元素
    textRef.value = text
    // 防止键盘在手机上显示
    textRef.setAttribute('readonly', '')
    // css3 渲染限制 不在视图内不渲染
    textRef.style.contain = 'strict'
    textRef.style.position = 'absolute'
    textRef.style.left = '-9999px'
    textRef.style.fontSize = '12pt' // 防止在iOS上缩放

    document.body.appendChild(textRef)
    textRef.select()
    // iOS的选择解决方案
    textRef.selectionStart = 0
    textRef.selectionEnd = text.length
    document.execCommand('copy')
    document.body.removeChild(textRef)
  }
}

鼠标滑动复制

鼠标滑动复制通过 document.execCommand('copy')进行复制

ts
/**
 * 鼠标滑动后复制
 */
export function mouseHoverCopy() {
  const selection = document.getSelection()
  // 鼠标滑动复制
  const originalRange = selection
    ? selection.rangeCount > 0 && selection.getRangeAt(0)
    : null

  if (originalRange) {
    // 清楚鼠标选中内容
    selection?.removeAllRanges()
    // 添加选中内容
    selection?.addRange(originalRange)
    document.execCommand('copy')
  }
}
/**
 * 获取选中内容
 */
export function getSelectText() {
  return document.getSelection()?.toString() || ''
}
/**
 * 鼠标滑动后复制
 */
export function mouseHoverCopy() {
  const selection = document.getSelection()
  // 鼠标滑动复制
  const originalRange = selection
    ? selection.rangeCount > 0 && selection.getRangeAt(0)
    : null

  if (originalRange) {
    // 清楚鼠标选中内容
    selection?.removeAllRanges()
    // 添加选中内容
    selection?.addRange(originalRange)
    document.execCommand('copy')
  }
}
/**
 * 获取选中内容
 */
export function getSelectText() {
  return document.getSelection()?.toString() || ''
}

封装日期函数绑定原型

TypeScript 文件下需要提前声明类型

点击查看
ts
export const n2 = (text: any) => text.toString().padStart(2, '0')

class DateTs extends Date {
  constructor(...args: any[]) {
    if (!args[0]) {
      super()
      return
    }
    if (args.length > 1) {
      super(...args as [number])
      return
    }
    if (args.length === 1 && ['string', 'number'].includes(typeof args[0])) {
      // TODO 处理传入的只有时间
      if (typeof args[0] === 'string' && !args[0].includes('-'))
        args[0] = `0000-00-00 ${args}`

      super(args[0])
    }
  }

  private o = {
    M: this.getMonth() + 1,
    d: this.getDate(),
    h: this.getHours(),
    m: this.getMinutes(),
    s: this.getSeconds(),
  }

  dateToArray(date: string) {
    return date.trim().split(/[-, ,:]/).map(Number)
  }

  /**
   * 格式化日期
   * @param {string} fmt yyyy-MM-dd hh:mm:ss
   */
  format(fmt = 'yyyy-MM-dd') {
    const fo = {
      'M+': this.getMonth() + 1,
      'd+': this.getDate(),
      'h+': this.getHours(),
      'm+': this.getMinutes(),
      's+': this.getSeconds(),
    }

    const yearRes = fmt.match(/y+/)
    if (yearRes)
      fmt = fmt.replace(/(y+)/, (`${this.getFullYear()}`).slice(0, yearRes[0].length))

    Object.entries(fo).forEach(([re, val]) => {
      const oRe = new RegExp(re)
      const resVal = String(fmt).match(oRe)

      if (resVal)
        fmt = fmt.replace(oRe, resVal[0].length === 1 ? val : n2(val))
    })
    return fmt
  }

  add(n: number, type: 'M' | 'd' | 'h' | 'm' | 's') {
    this.setDate(this.o[type] + n)
    return this
  }

  subtract(n: number, type: 'M' | 'd' | 'h' | 'm' | 's') {
    this.setDate(this.o[type] - n)
    return this
  }

  isSame(date: string, _type: string) {
    const fmtAbbr = ['y', 'M', 'd', 'h', 'm', 's']

    const format = date.replace(/\d+/g, (e) => {
      const t = fmtAbbr.shift()
      return Array.from({ length: e.length }).map(() => t).join('')
    })

    return this.format(format) === date
  }

  lastWeek() {
    const nowDay = this.getDate()
    const nowDayOfWeek = this.getDay()
    this.setDate(nowDay - (nowDayOfWeek || 7) - 6)
    return this.format('yyyy-MM-dd')
  }
}

export function datejs(date?: string | Date | number) {
  return new DateTs(date)
}
export const n2 = (text: any) => text.toString().padStart(2, '0')

class DateTs extends Date {
  constructor(...args: any[]) {
    if (!args[0]) {
      super()
      return
    }
    if (args.length > 1) {
      super(...args as [number])
      return
    }
    if (args.length === 1 && ['string', 'number'].includes(typeof args[0])) {
      // TODO 处理传入的只有时间
      if (typeof args[0] === 'string' && !args[0].includes('-'))
        args[0] = `0000-00-00 ${args}`

      super(args[0])
    }
  }

  private o = {
    M: this.getMonth() + 1,
    d: this.getDate(),
    h: this.getHours(),
    m: this.getMinutes(),
    s: this.getSeconds(),
  }

  dateToArray(date: string) {
    return date.trim().split(/[-, ,:]/).map(Number)
  }

  /**
   * 格式化日期
   * @param {string} fmt yyyy-MM-dd hh:mm:ss
   */
  format(fmt = 'yyyy-MM-dd') {
    const fo = {
      'M+': this.getMonth() + 1,
      'd+': this.getDate(),
      'h+': this.getHours(),
      'm+': this.getMinutes(),
      's+': this.getSeconds(),
    }

    const yearRes = fmt.match(/y+/)
    if (yearRes)
      fmt = fmt.replace(/(y+)/, (`${this.getFullYear()}`).slice(0, yearRes[0].length))

    Object.entries(fo).forEach(([re, val]) => {
      const oRe = new RegExp(re)
      const resVal = String(fmt).match(oRe)

      if (resVal)
        fmt = fmt.replace(oRe, resVal[0].length === 1 ? val : n2(val))
    })
    return fmt
  }

  add(n: number, type: 'M' | 'd' | 'h' | 'm' | 's') {
    this.setDate(this.o[type] + n)
    return this
  }

  subtract(n: number, type: 'M' | 'd' | 'h' | 'm' | 's') {
    this.setDate(this.o[type] - n)
    return this
  }

  isSame(date: string, _type: string) {
    const fmtAbbr = ['y', 'M', 'd', 'h', 'm', 's']

    const format = date.replace(/\d+/g, (e) => {
      const t = fmtAbbr.shift()
      return Array.from({ length: e.length }).map(() => t).join('')
    })

    return this.format(format) === date
  }

  lastWeek() {
    const nowDay = this.getDate()
    const nowDayOfWeek = this.getDay()
    this.setDate(nowDay - (nowDayOfWeek || 7) - 6)
    return this.format('yyyy-MM-dd')
  }
}

export function datejs(date?: string | Date | number) {
  return new DateTs(date)
}