Skip to content

第十二章 常用工具函数 (Utils配置)

前言

在项目开发中,我们经常会使用一些工具函数,也经常会用到例如loadsh等工具库,但是这些工具库的体积往往比较大,如果项目本身已经引入了这些工具库,那么我们就没有必要再引入一次,所以我们需要自己封装一些工具函数,来简化我们的开发。

一、通用类工具函数

src/utils目录下创建tools文件夹,用于存放通用类工具函数文件。 在tools文件下创建index.ts文件

typescript
import { ElMessage, MessageHandler } from 'element-plus'

/**
 * @description 文档注册enter事件
 * @param {Function} cb
 * @return {void}
 */
export function handleEnter(cb: Function): void {
  if (typeof cb !== 'function')
    return

  document.onkeydown = (e) => {
    const ev: KeyboardEventInit = e || window.event
    const keyCode = ev.code || ev.keyCode
    if (keyCode === 'Enter' || keyCode === 13)
      cb()
  }
}

/**
 * @description 日期格式化
 * @param {string | number} time {string like:{y}-{m}-{d} {h}:{i}:{s} } pattern
 * @return {string}
 */
export function parseTime(time: string | number, pattern: string) {
  if (arguments.length === 0 || !time)
    return null

  const format = pattern || '{y}-{m}-{d}'
  let date
  if (typeof time === 'object') {
    date = time
  }
  else {
    if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
      time = Number.parseInt(time)
    }
    else if (typeof time === 'string') {
      time = time
        .replace(new RegExp(/-/gm), '/')
        .replace('T', ' ')
        .replace(new RegExp(/\.[\d]{3}/gm), '')
    }
    if (typeof time === 'number' && time.toString().length === 10)
      time = time * 1000

    date = new Date(time)
  }
  const formatObj: Record<string, string> = {
    y: date.getFullYear(), // 年
    m: date.getMonth() + 1, // 月
    d: date.getDate(), // 日
    h: date.getHours(), // 时
    i: date.getMinutes(), // 分
    s: date.getSeconds(), // 秒
    a: date.getDay(), // 星期几
  }
  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
    let value = formatObj[key]
    // 注意:getDay()返回的是0表示星期天
    if (key === 'a')
      return ['日', '一', '二', '三', '四', '五', '六'][value]

    if (result.length > 0 && Number(value) < 10)
      value = `0${value}`

    return value || 0
  })
  return time_str
}

/**
 * @description trim函数
 * @param {string} str
 * @return {string}
 */
export function trim(str: string): string {
  return str.replace(/^\s+|\s+$/g, '') // 去除字符串两端的空格
}

/**
 * @description uuid的生成
 * @return {string}
 */
/**
 * @description 生成UUID
 * @return {string}
 */
export function getUUID(): string {
  const s: string[] = []
  const hexDigits = '0123456789abcdef'
  for (let i = 0; i < 36; i++) {
    s[i] = hexDigits[Math.floor(Math.random() * 0x10)]
  }
  s[14] = '4'
  s[19] = hexDigits[(parseInt(s[19], 16) & 0x3) | 0x8]
  s[8] = s[13] = s[18] = s[23] = '-'

  const uuid = s.join('')
  return uuid
}
// 38673f6b-bacc-4d9b-9330-dd97b7ae238f

/**
 * @description 千分位
 * @param {string | number} num
 * @return {void}
 */
export function addThousand(num: string | number): string {
  if (num)
    num = Number(num).toFixed(2)

  if ((!num && num !== 0) || num == 'NaN')
    return '--'
  const regForm = /(\d{1,3})(?=(\d{3})+(?:$|\.))/g
  num = num.toString().replace(regForm, '$1,')
  return num
}

/**
 * @description 大数值转换和保留n位有效数字
 * @param {number} num {number} digits
 * @return {string}
 */
export function numberFormatter(num: number, digits: number | undefined): string {
  const si = [
    { value: 1e13, symbol: '亿亿' },
    { value: 1e12, symbol: '万亿' },
    { value: 1e11, symbol: '千亿' },
    { value: 1e10, symbol: '百亿' },
    { value: 1e9, symbol: '十亿' },
    { value: 1e8, symbol: '亿' },
    { value: 1e7, symbol: '千万' },
    { value: 1e6, symbol: '百万' },
    { value: 1e5, symbol: '十万' },
    { value: 1e4, symbol: '万' },
    { value: 1e3, symbol: '千' },
  ]
  for (let i = 0; i < si.length; i++) {
    if (num >= si[i].value)
      return (num / si[i].value).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol
  }
  return num.toString()
}

/**
 * @description 复制方法
 * @param {string} value 传入要复制的值
 * @return {string | MessageHandler}
 */
export const copy = (value: string): string | MessageHandler => {
  if (!value)
    return ElMessage.error('复制失败')

  const tag = document.createElement('textarea')
  tag.value = value
  document.body.appendChild(tag)
  tag.select()
  document.execCommand('copy')
  ElMessage.success('复制成功')
  tag.remove()
  return value
}

/**
 * @description 防抖
 * @param {number} timer
 * @return {function}
 */
export function debounce(timer = 0): (callback: unknown, delay: number) => void {
  return (callback: unknown, delay: number) => {
    if (timer)
      clearTimeout(timer)

    if (typeof callback === 'function')
      timer = setTimeout(callback, delay)
  }
}

/**
 * @description 节流
 * @param {number} timer
 * @return {function}
 */
export const throttle: (fn: (...args: unknown[]) => void, timer: number) => (...args: unknown[]) => void = (fn, timer = 0) => {
  let time: number | null = null
  return (...args: unknown[]) => {
    if (time)
      clearTimeout(time)
    time = setTimeout(() => {
      fn.apply(this, args)
    }, timer)
  }
}

二、文件相关函数

tools文件下创建blobType.ts文件

typescript
export const blobType: Record<string, string> = {
  'aac': 'image/audio/aac',
  'abw': 'application/x-abiword',
  'arc': 'application/x-freearc',
  'avi': 'video/x-msvideo',
  'azw': 'application/vnd.amazon.ebook',
  'bin': 'application/octet-stream',
  'bmp': 'image/bmp',
  'bz': 'application/x-bzip',
  'bz2': 'application/x-bzip2',
  'csh': 'application/x-csh',
  'css': 'text/css',
  'csv': 'text/csv',
  'doc': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  'eot': 'application/vnd.ms-fontobject',
  'epub': 'application/epub+zip',
  'exe': 'application/x-msdownload',
  'gif': 'image/gif',
  'htm': 'text/html',
  'html': 'text/html',
  'ico': 'image/vnd.microsoft.icon',
  'ics': 'text/calendar',
  'jar': 'application/java-archive',
  'jpeg': 'image/jpeg',
  'jpg': 'image/jpeg',
  'js': 'text/javascript',
  'json': 'application/json',
  'jsonld': 'application/ld+json',
  'mid': 'audio/midi audio/x-midi',
  'midi': 'audio/midi audio/x-midi',
  'mjs': 'text/javascript',
  'mp3': 'audio/mpeg',
  'mpeg': 'video/mpeg',
  'mpkg': 'application/vnd.apple.installer+xml',
  'odp': 'application/vnd.oasis.opendocument.presentation',
  'ods': 'application/vnd.oasis.opendocument.spreadsheet',
  'odt': 'application/vnd.oasis.opendocument.text',
  'oga': 'audio/ogg',
  'ogv': 'video/ogg',
  'ogx': 'application/ogg',
  'otf': 'font/otf',
  'png': 'image/png',
  'pdf': 'application/pdf',
  'ppt': 'application/vnd.ms-powerpoint',
  'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  'rar': 'application/x-rar-compressed',
  'rtf': 'application/rtf',
  'sh': 'ima',
  'svg': 'image/svg+xml',
  'swf': 'application/x-shockwave-flash',
  'tar': 'application/x-tar',
  'tif': 'image/tiff',
  'tiff': 'image/tiff',
  'ttf': 'font/ttf',
  'txt': 'text/plain',
  'vsd': 'application/vnd.visio',
  'wav': 'audio/wav',
  'weba': 'audio/webm',
  'webm': 'video/webm',
  'webp': 'image/webp',
  'woff': 'font/woff',
  'woff2': 'font/woff2',
  'xhtml': 'application/xhtml+xml',
  'xls': 'application/vnd.ms-excel',
  'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  'xml': 'text/xml',
  'xul': 'application/vnd.mozilla.xul+xml',
  'zip': 'application/zip',
  '3gp': 'video/3gpp',
  '3g2': 'video/3gpp2',
  '7z': 'application/x-7z-compressed',
}

tools文件下创建file.ts文件

typescript
import { ElMessage } from 'element-plus'
import { blobType } from './blobType'

export function download(file: any, fileType: string, fileName?: string) {
  if (!fileName) {
    const timeStr = new Date().getTime()
    fileName = `${timeStr}`
  }
  const type = formatFileType(fileType)
  if (!type)
    return ElMessage.warning('暂不支持此格式!')
  const blob = new Blob([file], { type })
  const downloadElement = document.createElement('a')
  const href = window.URL.createObjectURL(blob) // 创建下载的链接
  downloadElement.href = href
  downloadElement.download = fileName // 下载后文件名
  document.body.appendChild(downloadElement)
  downloadElement.click() // 点击下载
  document.body.removeChild(downloadElement) // 下载完成移除元素
  window.URL.revokeObjectURL(href) // 释放掉blob对象
}

export function formatFileType(fileFormat: string) {
  return blobType[fileFormat]
}

export function blobToFileReader(blob: any, callback: any) {
  if (!blob.size)
    return ElMessage.warning('暂无资源!')
  if (blob.type !== 'application/json')
    return callback(blob)
  const fr: any = new FileReader()
  fr.onloadend = function () {
    try {
      callback(JSON.parse(fr.result))
    }
    catch (err) {
      ElMessage.warning('资源数据有误!')
    }
  }
  fr.readAsText(blob)
}

三、存储相关函数

src/utils目录下创建cache文件夹,用于存放存储类工具函数文件。 在cache文件夹下创建index.ts文件

typescript
/**
 * window.localStorage 浏览器永久缓存
 * @method set 设置永久缓存
 * @method get 获取永久缓存
 * @method remove 移除永久缓存
 * @method clear 移除全部永久缓存
 */
export const Local = {
  // 设置永久缓存
  set(key: string, val: any) {
    window.localStorage.setItem(key, JSON.stringify(val))
  },

  // 获取永久缓存
  get(key: string) {
    const json: any = window.localStorage.getItem(key)
    return JSON.parse(json)
  },

  // 移除永久缓存
  remove(key: string) {
    window.localStorage.removeItem(key)
  },

  // 移除全部永久缓存
  clear() {
    window.localStorage.clear()
  },
}

/**
 * window.sessionStorage 浏览器临时缓存
 * @method set 设置临时缓存
 * @method get 获取临时缓存
 * @method remove 移除临时缓存
 * @method clear 移除全部临时缓存
 */
export const Session = {
  // 设置临时缓存
  set(key: string, val: any) {
    window.sessionStorage.setItem(key, JSON.stringify(val))
  },

  // 获取临时缓存
  get(key: string) {
    const json: any = window.sessionStorage.getItem(key)
    return JSON.parse(json)
  },

  // 移除临时缓存
  remove(key: string) {
    window.sessionStorage.removeItem(key)
  },

  // 移除全部临时缓存
  clear() {
    window.sessionStorage.clear()
  },
}

file-tree

总结

工具函数的封装,可以提高代码的复用性,降低维护成本,本文只是介绍了一小部分工具函数的封装,更多的工具函数的封装,可以参考lodash等函数工具库,也可以根据实际需求,封装自己的工具函数。上文中的配置代码可在 github 仓库中直接 copy,仓库路径:https://github.com/SmallTeddy/ProjectConstructionHub