博客项目全栈开发 后台管理系统 第二章:工具函数

#『技术文档』写作方法征文挑战赛#

前言

在前段开发中,函数的重要性不用多说,更别提现在都用的函数式编程。建议大家按顺序稍微看一眼。
1.字符串处理:如截取、拼接、替换、转换大小写等。通过这些函数,可以方便地处理字符串数据,满足不同的业务需求。
2.数组操作:例如排序、过滤、查找、去重等。这些工具函数能够处理数组数据,实现常见的数组操作,并提供便捷的方法来处理数组元素。
3.时间处理:比如格式化、计算时间差、转换时间戳等。这些函数简化了时间操作,使得时间处理变得更加方便和可控。
4.数据校验:包括验证手机号、邮箱、身份证号、密码强度等。这些函数可以帮助前端开发者在表单提交前对用户输入的数据进行校验,提高数据的完整性和准确性。
5.DOM操作:如获取元素、添加、删除、修改样式等。通过这些函数,可以方便地操作DOM元素,在页面上实现各种交互效果。
6.es6里的箭头函数以及函数式编程!!!
言归正传,为什么需要工具函数,答案有很多,比如不够灵活等等,最简单的例子,转换年月日,大家可以去试试。好了,正式开始吧。

集合

/**
 * 工具函数集合
 * @description 包含常用的工具函数,如防抖、节流、日期格式化等
 */

/**
 * 防抖函数
 * @description 在一定时间内,多次触发同一函数,只执行最后一次
 * @param {Function} fn 需要防抖的函数
 * @param {number} delay 延迟时间,单位毫秒
 * @returns {Function} 防抖后的函数
 * @example
 * const handleSearch = debounce((value) => {
 *   console.log('搜索:', value)
 * }, 300)
 * 
 * // 在输入框中使用
 * <input @input="handleSearch" />
 */
export function debounce(fn, delay = 300) {
  let timer = null
  return function (...args) {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(this, args)
    }, delay)
  }
}

/**
 * 节流函数
 * @description 在一定时间内,多次触发同一函数,只执行第一次
 * @param {Function} fn 需要节流的函数
 * @param {number} delay 延迟时间,单位毫秒
 * @returns {Function} 节流后的函数
 * @example
 * const handleScroll = throttle(() => {
 *   console.log('滚动事件')
 * }, 300)
 * 
 * // 在滚动事件中使用
 * window.addEventListener('scroll', handleScroll)
 */
export function throttle(fn, delay = 300) {
  let timer = null
  let startTime = Date.now()
  return function (...args) {
    const curTime = Date.now()
    const remaining = delay - (curTime - startTime)
    if (timer) clearTimeout(timer)
    if (remaining <= 0) {
      fn.apply(this, args)
      startTime = Date.now()
    } else {
      timer = setTimeout(() => {
        fn.apply(this, args)
        startTime = Date.now()
      }, remaining)
    }
  }
}

/**
 * 深拷贝
 * @description 创建一个对象的深拷贝,避免引用类型数据修改影响原数据
 * @param {*} obj 需要深拷贝的对象
 * @returns {*} 深拷贝后的对象
 * @example
 * const obj = { a: 1, b: { c: 2 } }
 * const clone = deepClone(obj)
 * clone.b.c = 3
 * console.log(obj.b.c) // 2
 */
export function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj
  const clone = Array.isArray(obj) ? [] : {}
  for (let key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      clone[key] = deepClone(obj[key])
    }
  }
  return clone
}

/**
 * 格式化日期
 * @description 将日期格式化为指定格式的字符串
 * @param {Date|string|number} date 日期
 * @param {string} fmt 格式化模式,如 'YYYY-MM-DD HH:mm:ss'
 * @returns {string} 格式化后的日期字符串
 * @example
 * formatDate(new Date(), 'YYYY年MM月DD日') // 2024年03月21日
 * formatDate(new Date(), 'HH:mm:ss') // 14:30:00
 */
export function formatDate(date, fmt = 'YYYY-MM-DD HH:mm:ss') {
  if (!date) return ''
  date = new Date(date)
  const o = {
    'M+': date.getMonth() + 1,
    'D+': date.getDate(),
    'H+': date.getHours(),
    'm+': date.getMinutes(),
    's+': date.getSeconds(),
    'q+': Math.floor((date.getMonth() + 3) / 3),
    'S': date.getMilliseconds()
  }
  
  if (/(Y+)/.test(fmt)) {
    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
  }
  
  for (let 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
}

/**
 * 获取文件扩展名
 * @description 从文件名中获取文件扩展名
 * @param {string} filename 文件名
 * @returns {string} 文件扩展名
 * @example
 * getFileExt('test.jpg') // jpg
 * getFileExt('document.pdf') // pdf
 */
export function getFileExt(filename) {
  return filename.substring(filename.lastIndexOf('.') + 1)
}

/**
 * 格式化文件大小
 * @description 将文件大小(字节)转换为可读的字符串
 * @param {number} bytes 文件大小(字节)
 * @returns {string} 格式化后的文件大小
 * @example
 * formatFileSize(1024) // 1 KB
 * formatFileSize(1024 * 1024) // 1 MB
 */
export function formatFileSize(bytes) {
  if (bytes === 0) return '0 B'
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

/**
 * 生成随机字符串
 * @description 生成指定长度的随机字符串
 * @param {number} length 字符串长度
 * @returns {string} 随机字符串
 * @example
 * randomString(8) // a1b2c3d4
 * randomString(16) // a1b2c3d4e5f6g7h8
 */
export function randomString(length = 32) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  let result = ''
  for (let i = 0; i < length; i++) {
    result += chars.charAt(Math.floor(Math.random() * chars.length))
  }
  return result
}

/**
 * 获取URL参数
 * @description 从URL中获取指定参数的值
 * @param {string} name 参数名
 * @returns {string|null} 参数值
 * @example
 * // URL: http://example.com?name=test&age=18
 * getUrlParam('name') // test
 * getUrlParam('age') // 18
 */
export function getUrlParam(name) {
  const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)')
  const r = window.location.search.substr(1).match(reg)
  if (r != null) return decodeURIComponent(r[2])
  return null
}

/**
 * 树形数据转换
 * @description 将扁平数组转换为树形结构
 * @param {Array} data 数据
 * @param {string} id id字段
 * @param {string} pid 父id字段
 * @param {string} children 子节点字段
 * @returns {Array} 树形数据
 * @example
 * const data = [
 *   { id: 1, pid: 0, name: '父节点' },
 *   { id: 2, pid: 1, name: '子节点' }
 * ]
 * arrayToTree(data) // [{ id: 1, pid: 0, name: '父节点', children: [{ id: 2, pid: 1, name: '子节点' }] }]
 */
export function arrayToTree(data, id = 'id', pid = 'pid', children = 'children') {
  const result = []
  const map = {}
  
  data.forEach(item => {
    map[item[id]] = item
  })
  
  data.forEach(item => {
    const parent = map[item[pid]]
    if (parent) {
      (parent[children] || (parent[children] = [])).push(item)
    } else {
      result.push(item)
    }
  })
  
  return result
}

/**
 * 树形数据扁平化
 * @description 将树形结构转换为扁平数组
 * @param {Array} data 树形数据
 * @param {string} children 子节点字段
 * @returns {Array} 扁平数组
 * @example
 * const tree = [
 *   { id: 1, children: [{ id: 2 }] }
 * ]
 * treeToArray(tree) // [{ id: 1 }, { id: 2 }]
 */
export function treeToArray(data, children = 'children') {
  const result = []
  const flatten = (arr) => {
    arr.forEach(item => {
      result.push(item)
      if (item[children] && item[children].length) {
        flatten(item[children])
      }
    })
  }
  flatten(data)
  return result
}

/**
 * 获取数据类型
 * @description 获取值的具体数据类型
 * @param {*} value 需要判断的值
 * @returns {string} 数据类型
 * @example
 * getType([]) // array
 * getType({}) // object
 * getType('') // string
 */
export function getType(value) {
  return Object.prototype.toString.call(value).slice(8, -1).toLowerCase()
}

/**
 * 判断是否为空值
 * @description 判断值是否为空(null、undefined、空字符串、空数组、空对象)
 * @param {*} value 需要判断的值
 * @returns {boolean} 是否为空
 * @example
 * isEmpty(null) // true
 * isEmpty('') // true
 * isEmpty([]) // true
 * isEmpty({}) // true
 */
export function isEmpty(value) {
  if (value === null || value === undefined) return true
  if (typeof value === 'string' && value.trim() === '') return true
  if (Array.isArray(value) && value.length === 0) return true
  if (typeof value === 'object' && Object.keys(value).length === 0) return true
  return false
}

以后有用到其他函数会在加上,暂时就这些了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值