前端新手Vue3+Vite+Ts+Pinia+Sass项目指北系列文章 —— 第十二章 常用工具函数 (Utils配置)

前言

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

一、通用类工具函数

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

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文件

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文件

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文件

/**
 * 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()
  },
}

在这里插入图片描述

总结

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

写在最后

经过一段时间的整理和书写,前端新手Vue3+Vite+Ts+Pinia+Sass项目指北系列文章已经全部更新完了,感谢各位小伙伴的支持与厚爱,文章中可能有一些依赖部分会有所更新,最后依赖版本号请参考仓库中的地址进行对照。前端道路道阻且长,富而杂,多而繁,请各位取长补短,各自努力绽放。

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你好!对于使用 Vue 3、TypeScript 和 Vite 来搭建项目,并结合 Pinia 进行状态管理,你可以按照以下步骤进行操作: 1. 首先,确保你已经安装了 Node.js 和 npm(或者使用 yarn)。 2. 创建一个新的项目文件夹,并进入该文件夹。 3. 在终端中运行以下命令来初始化一个新的 Vue 3 项目: ``` npm init vite@latest ``` 在初始化过程中,选择使用 Vue 3、TypeScript 和默认配置。 4. 进入项目文件夹并安装依赖: ``` cd <project-folder> npm install ``` 5. 接下来,安装 Pinia: ``` npm install pinia ``` 6. 在 `src` 目录下创建一个 `store` 文件夹,并在其中创建名为 `index.ts` 的文件。 7. 在 `index.ts` 中编写你的 Pinia store。例如,你可以创建一个名为 `counter` 的 store,并且在其中定义一个状态和一些操作: ```typescript import { defineStore } from 'pinia'; export const useCounterStore = defineStore('counter', { state: () => ({ count: 0, }), actions: { increment() { this.count++; }, decrement() { this.count--; }, }, }); ``` 8. 在应用的入口文件 `main.ts` 中导入并使用 Pinia: ```typescript import { createApp } from 'vue'; import { createPinia } from 'pinia'; import App from './App.vue'; const app = createApp(App); const pinia = createPinia(); app.use(pinia); app.mount('#app'); ``` 9. 在组件中使用 Pinia store。在你的 Vue 组件中,可以使用 `useStore` 函数来访问 Pinia store: ```typescript import { useCounterStore } from '../store'; export default { setup() { const counterStore = useCounterStore(); return { counterStore, }; }, }; ``` 10. 最后,你可以在组件中使用 `counterStore` 来访问状态和操作: ```vue <template> <div> <p>{{ counterStore.count }}</p> <button @click="counterStore.increment()">Increment</button> <button @click="counterStore.decrement()">Decrement</button> </div> </template> <script> import { useCounterStore } from '../store'; export default { setup() { const counterStore = useCounterStore(); return { counterStore, }; }, }; </script> ``` 这样,你就可以使用 Vue 3、TypeScript、Vite 和 Pinia 搭建一个基本的项目并进行状态管理了。希望对你有帮助!如果还有其他问题,请随时问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SmallTeddy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值