目录
# 核心包,包含绝大部分 utils
pnpm add @utopia-utils/core
# 仅安装 Vue Composables (Vue 3)
pnpm add @utopia-utils/vueuse
# 仅安装 DOM 相关 utils
pnpm add @utopia-utils/dom
# 仅安装树结构相关 utils
pnpm add @utopia-utils/tree
# 仅安装类型判断相关 utils
pnpm add @utopia-utils/share
# 仅安装 CLI 工具
pnpm add @utopia-utils/cli- average: 计算数组的平均值,支持
object数组。source - sum: 计算数组的和,支持
object数组。source - sort: 数组排序,支持
object数组。source - alphabetical: 数组按字母顺序排序,支持
object数组。source - unique: 数组去重。source
- union: 数组并集。source
- uniqueWith: 数组去重,使用自定义的比较函数。source
- intersection: 两个数组交集。source
- groupBy: 数组根据指定的 key 分组。source
- arrLast: 获取数组最后一个元素。source
- arrayToCSV: 数组转换为 CSV 字符串。source
- defineDictionary: 定义业务字典,类型安全。 source
- objectKeys: 带类型的
Object.keys()。source - omit: 删除
object对象的指定属性。source - pick: 从
object对象中获取指定属性。source - getByPath: 通过路径获取对象的值,类型安全。source
- setByPath: 通过路径设置对象的值,类型安全。source
- deepClone: 深拷贝。source
- deepEqual: 深比较。source
- merge: 深合并两个对象,返回一个新对象。source
- merge.all: 深合并多个对象到一个新对象。source
- compose: 函数组合, 从右到左执行。source
- pipe: 函数组合, 从左到右执行。source
- memoize: 创建一个会缓存返回结果的函数。source
- callLimit: 限制函数调用次数。source
- once: 限制函数只能调用一次。source
- debounce: 防抖。source
- throttle: 节流。source
- measurePerformance: 测量函数执行性能,返回执行耗时。source
- sleep: 等待指定的时间。source
- retry: 重试函数(如果函数抛出错误)直到成功或者达到最大重试次数。source
- to: 一个让你在 async/await 中轻松处理错误的装饰器,免于使用 try-catch。source
- onlyResolvesLast: 解决竞态问题,只保留最后一次调用的结果。source
- onTimeout:
setTimeout的封装, 返回一个清除定时器的函数。source - createPoll: 创建一个轮询器。source
- createControlledPromise: 创建一个可控的 Promise。source
- randomString: 随机生成指定长度、指定字符集的字符串。source
- capitalize: 首字母大写。source
- escapeStringRegexp: 把字符串中的特殊字符转义为它可以在正则表达式中使用的形式。source
- encryptPhone: 加密手机号, 中间 4 位显示成
*。source - formatterBankCard: 银行卡号格式化。source
- formatterPhoneNumber: 手机号格式化。source
- formatterIdCard: 身份证呈格式化。source
- desensitizeName: 姓名脱敏。source
- desensitizePhone: 手机号脱敏。source
- desensitizeIDCard: 身份证脱敏。source
- desensitizeEmail: 邮箱脱敏。source
- toUpperFirstLetter: 首字母转大写。source
- randomInt: 生成指定范围内
[min, max]的整数。source - toFixedWithoutZeros:
Number.toFixed并移除末尾的零。source - formatNumberThousand: 数字千分位格式化。source
- yuanToFen: 人民币:元转分。source
- fenToYuan: 人民币:分转元。source
- yuanFormat: 人民币格式化(单位默认是分,会进行分转元再格式化)。source
- NP: 解决浮点数计算精度问题。source
- getQueryParams: 从 URL 中解析查询参数。source
- parseQuery: 解析 url query。source
- base64ToFile: base64 转 File, 如图片裁剪时,我们获取到的是 base64,但上传接口一般需要 formData 上传。source
- toBase64: 将
File|Blob|imgUrl转 base64。source
- breadthFirstTraverse: 广度优先遍历。source
- deepFirstTraverse: 深度优先遍历。source
- treeFindNode: 查找符合条件的单个节点或多个节点,通过广度优先遍历查找。source
- buildTreeFromList: 列表结构转树结构。source
- flattenTree: 树结构转列表结构(打平)。source
- treeFindPath: 查打符合条件节点的路径。source
- treeFilterNode: 过滤不符合条件的树节点。source
- useSmsCountdown: 短信验证码倒计时的 Vue composable 函数,提供完整的验证码发送倒计时功能。支持自定义倒计时时长、控制发送状态、自定义显示文本等。source
- useTable: 表格状态管理 Hook 的简单封装,减少模板代码。提供分页、排序、过滤和搜索功能的完整解决方案。支持简单搜索模式(实时搜索)和高级搜索模式(手动搜索)。source
- useFakeProgress: 可控的假进度条 Hook,支持自动递增、手动控制、自定义递增算法,提供进度变化/完成回调,适用于上传、异步加载等场景。source
- useDelayedLoading: 延迟显示与最小显示时间控制的 loading 状态管理 Hook,可有效避免短请求导致的 loading 闪烁问题。source
- useDeferredToggle: 传入原始 open / hide 方法,返回带防闪烁逻辑的新 open / hide。。source
- waitForSelector: 等待指定的选择器匹配的元素出现在页面中,如果调用此方法时已经有匹配的元素,那么此方法立即返回。 如果指定的选择器在超时时间后扔不出现,返回
null。source - panzoom: 为指定的元素添加拖拽缩放功能。source
- domContains: 原生
Node.contains()的兼容写法 。source - dynamicCSS: 注入 css 样式(通过动态插入 style 标签)。source
- loadCSS: 动态加载 CSS。source
- loadScript: 动态加载脚本。source
- setCssVar: 设置
css变量。 source
- canUseDom: 判断是否可以使用
document和window对象,判断是否是 ssr 场景。source - isAlipay: 判断是否是支付宝浏览器。source
- isAndroid: 判断是否是 Android 系统。source
- isIOS: 判断是否是 IOS 系统。source
- isWeixin: 判断是否是微信浏览器。source
- isMobile: 判断是否是移动端浏览器。source
- checkWebpFeature: 检测浏览器是否支持 webp 的一些特性('lossy' | 'lossless' | 'alpha' | 'animation')。source
- checkWebpSupport: 检测浏览器是否支持 webp。source
- onWindowFocus: 监听
window focus和visibilitychange事件,当窗口可见时,触发回调。source - Cookies: 操作 Cookie 的工具函数。source
isBooleanisStringisNumberisFunctionisSymbolisArrayisRegExpisMapisPromiseisSetisDateisPlainObjectisObjectisIntegerKeyisUndefisDef- isEmpty: 检查值是否为空(例如
'',[],{})。source - isNumberLike: 检查值是否像一个数字(例如
'123')。source - isValidUrl: 检查字符串是否为有效的 URL。source
- isPositiveNumber: 检查值是否为正数。source
- isNegativeNumber: 检查值是否为负数。source
- isKeyOf: 检查一个 key 是否为对象的属性,类型安全。source
- toTypeString: 获取值的具体类型字符串,比
typeof更精确。source
- getGitCommitHash: 获取当前 Git 提交的哈希值。source
- isDirector: 判断指定路径是否为目录。source
- isFile: 判断指定路径是否为文件。source
- pathExists: 判断指定路径是否存在。source
- getFileName: 获取文件名。source
- mitt: 轻量级的事件发布/订阅库。source
- createDeferredToggle: 传入原始 open / hide 方法,返回带防闪烁逻辑的新 open / hide。source
createEnumFromOptions: 通过options自动生成对应的enum, 后期只需要维护options。typesafe。source已废弃, 请使用 defineDictionary 代替。
@utopia-utils/core重新导出了下面这些优秀的第三方库,方便直接使用。
- debounce: 函数防抖。
- throttle: 函数节流。
- js-cookie: 轻量级的浏览器 cookie 操作库。
- mitt: 仅 200 字节的函数式事件发布/订阅库,类型安全。
- deepmerge: 深度合并对象的库。
- number-precision: 解决浮点数计算精度问题的库。
file-saver: An HTML5 saveAs() FileSaver implementation.zod: TypeScript-first schema validation with static type inference.dayjs: ⏰ Day.js 2kB immutable date-time library alternative to Moment.js with the same modern API.any-rule: 常用正则大全。fast-deep-equal: The fastest deep equality check with Date, RegExp and ES6 Map, Set and typed arrays support.big.js: 一个小型,快速的 JavaScript 库,用于任意精度的十进制算术运算。browser-image-compression: Javascript module to be run in the web browser for image compression.hashids: generate YouTube-like ids from numbers.
定义业务字典, 类型安全
// at src/constant.ts
const { get_MUSIC_TYPE_KEYS, get_MUSIC_TYPE_KV, get_MUSIC_TYPE_MAP, get_MUSIC_TYPE_MAP_BY_KEY, get_MUSIC_TYPE_MAP_BY_VALUE, get_MUSIC_TYPE_OPTIONS, get_MUSIC_TYPE_VALUES, get_MUSIC_TYPE_VK } = defineDictionary([
{
key: 'POP',
value: 1,
label: '流行音乐',
color: 'red',
},
{
key: 'ROCK',
value: 2,
label: '摇滚音乐',
color: 'blue',
},
] as const, 'MUSIC_TYPE') // !!! 必须使用 as const 来保证类型安全
export const MUSIC_TYPE_KEYS = get_MUSIC_TYPE_KEYS()
// ['POP', 'ROCK']
export const MUSIC_TYPE_VALUES = get_MUSIC_TYPE_VALUES()
// [1, 2]
export const MUSIC_TYPE_KV = get_MUSIC_TYPE_KV()
// { POP: 1, ROCK: 2 }
export const MUSIC_TYPE_VK = get_MUSIC_TYPE_VK()
// { 1: 'POP', 2: 'ROCK' }
export const MUSIC_TYPE_MAP_BY_KEY = get_MUSIC_TYPE_MAP_BY_KEY()
// {
// POP: { key: 'POP', value: 1, label: '流行音乐', color: 'red' },
// ROCK: { key: 'ROCK', value: 2, label: '摇滚音乐', color: 'blue' }
// }
export const MUSIC_TYPE_MAP_BY_VALUE = get_MUSIC_TYPE_MAP_BY_VALUE()
// {
// 1: { key: 'POP', value: 1, label: '流行音乐', color: 'red' },
// 2: { key: 'ROCK', value: 2, label: '摇滚音乐', color: 'blue' }
// }
export const MUSIC_TYPE_MAP = get_MUSIC_TYPE_MAP()
// { POP: 1, ROCK: 2 }
export const MUSIC_TYPE_OPTIONS = get_MUSIC_TYPE_OPTIONS()
// [
// { key: 'POP', value: 1, label: '流行音乐', color: 'red' },
// { key: 'ROCK', value: 2, label: '摇滚音乐', color: 'blue' }
// ]已废弃, 请使用 defineDictionary 代替。
通过 options 自动生成对应的 enum, 后期只需要维护 options。类型安全
// example
const optionsLevel = [
{
value: 0,
label: 'level1',
},
{
value: 1,
label: 'level2',
},
] as const // 必须使用 as const 来保证类型安全
const enumLevel = createEnumFromOptions(optionsLevel)
console.log(enumLevel.level1) // 0
console.log(enumLevel['0']) // 'level1'
console.log(enumLevel)
// {
// "0": "level1",
// "1": "level2",
// "level1": 0,
// "level2": 1
// }重试函数(如果函数抛出错误)直到成功或者达到最大重试次数。
let callNum = 0
function fn() {
callNum++
return Promise.reject(new Error('foo'))
}
const [err, res] = await retry(fn, 2, (attemptTime) => {
return attemptTime * 5
})
// err 是 Error, res 是 null, callNum 是 3
// 总执行时间 >= 15ms (5ms + 10ms)所有的 Tree utils 支持自定义 fieldNames
export interface FieldNames { id?: string children?: string parentId?: string }
广度优先遍历。
// example
const tree = [
{
name: 'a',
Children_: [
{ name: 'b' },
],
},
{
name: 'c',
},
]
breadthFirstTraverse(tree, node => console.log(node.name), {
fieldNames: {
children: 'Children_', // 默认为 'children'
},
})
// output 'a', 'c', 'b'查找符合条件的单个节点或多个节点,通过广度优先遍历查找。
// example
const tree = [
{
name: 'a',
children: [
{ name: 'b' },
],
}
]
const res = treeFindNode(tree, node => node.name === 'b') // res is [{ name: 'b' }]列表结构转树结构。
// example
const list = [
{ uid: '1', title: 'node 1', pid: '' },
{ uid: '1-1', title: 'node 1-1', pid: '1' },
{ uid: '1-2', title: 'node 1-2', pid: '1' },
{ uid: '1-1-1', title: 'node 1-1-1', pid: '1-1' },
]
interface TreeNode {
key: string
title: string
children: TreeNode[]
pid: string
}
const tree = buildTreeFromList<TreeNode>(list, {
listFieldNames: { id: 'uid', parentId: 'pid' },
treeFieldNames: { id: 'key', parentId: 'pid', children: 'children' },
})打平,树结构转列表结构。
// example
const tree = {
id: 1,
children: [
{
id: 2,
},
],
}
const list = flattenTree(tree)
console.log(list)
// output
// [
// {
// "id": 1,
// "children": [
// {
// "id": 2,
// },
// ],
// },
// {
// "id": 2,
// },
// ]查打符合条件节点的路径。
// example
const tree = [
{
name: 'a',
children: [
{ name: 'b' },
],
},
{
name: 'c',
},
]
const path = treeFindPath(tree, node => node.name === 'b')
console.log(path?.map(v => v.name)) // ['a', 'b']过滤不符合条件的树节点。
const tree = [
{
id: 'root',
children: [
{
id: 'child1',
},
{
id: 'child2',
},
],
},
]
treeFilterNode(tree, node => node.id.includes('1'))
// output
// [
// {
// children: [
// {
// id: 'child1',
// },
// ],
// id: 'root',
// },
// ]