pen-it
v1.0.6
Published
用笔锚定记忆中的前端常用工具函数,一个轻量级的前端实用程序库,支持类型检查、日期/数字格式化、字符串操作、数据存储、深度克隆、数组操作、Cookie 以及浏览器 API
Maintainers
Readme
pen-it
用笔锚定记忆中的前端常用工具函数,一个轻量级的前端实用程序库,支持类型检查、日期/数字格式化、字符串操作、数据存储、深度克隆、数组操作、Cookie 以及浏览器 API
安装
pnpm add pen-it使用
import { isArray, formatFull, deepClone, unique } from 'pen-it'API
类型判断 — is
isArray(value)— 判断是否为数组。isArray([1, 2, 3]) // trueisObject(value)— 判断是否为对象(不含数组)。isObject({ a: 1 }) // trueis(val, type)— 通用类型判断(内部工具)。is([], 'Array') // trueisFunction(val)— 判断是否为函数。isFunction(() => {}) // trueisAsyncFunction(val)— 判断是否为异步函数。isAsyncFunction(async () => {}) // trueisPromise(value)— 判断是否为 Promise。isPromise(Promise.resolve()) // trueisDate(val)— 判断是否为 Date 对象。isDate(new Date()) // trueisNumber(val)— 判断是否为数字(含 NaN/Infinity)。isNumber(42) // trueisInt(val)— 判断是否为整数。isInt(42) // trueisFloat(val)— 判断是否为浮点数。isFloat(3.14) // trueisString(val)— 判断是否为字符串。isString('hello') // trueisBoolean(val)— 判断是否为布尔值。isBoolean(true) // trueisSymbol(value)— 判断是否为 Symbol。isSymbol(Symbol('foo')) // trueisPrimitive(value)— 判断是否为原始类型。isPrimitive(42) // trueisNull(val)— 判断是否为 null。isNull(null) // trueisDef(val)— 判断是否不是 undefined。isDef('hello') // trueisUnDef(val)— 判断是否为 undefined。isUnDef(undefined) // trueisNullOrUnDef(val)— 判断是否为 null 或 undefined。isNullOrUnDef(null) // trueisEmpty(value)— 判断是否为空(完备版:支持 Date/Map/Set 等)。isEmpty('') // true isEmpty([]) // true isEmpty({}) // trueisEmptySv(value)— 判断是否为空(简化版)。isEmptySv([]) // trueisEqual(x, y)— 深度相等比较(支持 Date/RegExp)。isEqual({ a: 1 }, { a: 1 }) // trueisHexColor(str)— 判断是否为十六进制颜色。isHexColor('#fff') // trueisValidEmail(email)— 判断是否为有效邮箱。isValidEmail('[email protected]') // trueisPC()— 判断是否为浏览器环境。isPC() // trueisWindow(val)— 判断是否为 window 对象。isWindow(window) // trueisElement(val)— 判断是否为 DOM 元素。isElement(document.body) // trueisIOS()— 判断设备是否为 iOS。isIOS() // true
日期时间格式化 — format
formatFull(date)— 完整日期时间(斜杠分隔)。formatFull(new Date()) // "2026/06/03 14:30:45"formatFullReplace(date)— 完整日期时间(短横线分隔)。formatFullReplace(new Date()) // "2026-06-03 14:30:45"formatYMD(date)— 中文年月日。formatYMD(new Date()) // "2026年6月3日"formatWeek(date)— 星期几。formatWeek(new Date()) // "星期三"
数字与货币格式化 — format
formatRmb(value, options)— 货币格式化(人民币)。formatRmb(1234.56, { type: 'zh-CN', currency: 'CNY' }) // "¥1,234.56"formatNum(value)— 千位分隔符。formatNum(1234567) // "1,234,567"percentCN(value, digit)— 百分比格式化。percentCN(0.1234, 2) // "12.34%"compactEN(value)— 大数简化(英文缩写)。compactEN(12345) // "12K"compactCN(value)— 大数简化(中文缩写)。compactCN(12345) // "1.2万"signed(value, digit)— 带正负号显示。signed(42, 1) // "+42.0"
字符串处理 — format
maskPhone(phone)— 手机号脱敏(隐藏中间4位)。maskPhone('13812345678') // "138****5678"spacePhone(phone)— 手机号空格分隔。spacePhone('13812345678') // "138 1234 5678"capitalize(str)— 每个单词首字母大写。capitalize('hello world') // "Hello World"kebabToCamel(str)— 短横线转小驼峰。kebabToCamel('hello-world') // "helloWorld"camelToKebab(str)— 驼峰转短横线。camelToKebab('helloWorld') // "hello-world"toCamel(str)— 下划线转驼峰。toCamel('hello_world') // "helloWorld"firstUpper(str)— 首字母大写。firstUpper('hello') // "Hello"firstLower(str)— 首字母小写。firstLower('Hello') // "hello"reverse(str)— 反转字符串。reverse('hello') // "olleh"trimAll(str)— 去除所有空格。trimAll(' h e l lo ') // "hello"truncate(str, max, suffix?)— 超长文本截断。truncate('Hello World', 8) // "Hello..."truncateByWords(str, max, suffix?)— 按字数截断(中文友好)。truncateByWords('你好世界欢迎你', 4) // "你好世界..."
存储 — storage
localGet<T>(key)— 获取 localStorage(自动 JSON 解析)。localGet('user') // { name: '张三' }localSet(key, value)— 设置 localStorage(自动 JSON 序列化)。localSet('user', { name: '张三' })localRm(key)— 移除指定 localStorage。localRm('user')localClear()— 清除所有 localStorage。localClear()
拷贝 — copy
deepClone(obj)— 递归深拷贝(支持 Date/RegExp/Map/Set/循环引用)。deepClone({ a: 1, b: { c: 2 } })deepCloneWithJSON(obj)— JSON 深拷贝(仅 JSON 安全类型)。deepCloneWithJSON({ a: 1 })shallowClone(obj)— 浅拷贝(仅第一层)。shallowClone({ a: 1, b: { c: 2 } })
数组 — array
unique(arr)— Set 去重。unique([1, 2, 2, 3]) // [1, 2, 3]uniqueByKey(arr, key)— 对象数组按 key 去重。uniqueByKey([{ id: 1 }, { id: 1 }], 'id')sortNumAsc(arr)— 数值升序。sortNumAsc([3, 1, 2]) // [1, 2, 3]sortNumDesc(arr)— 数值降序。sortNumDesc([1, 3, 2]) // [3, 2, 1]sortByKey(arr, key, order?)— 按对象属性排序。sortByKey([{ age: 30 }, { age: 20 }], 'age')toArray(arrayLike)— 类数组转数组。toArray(document.querySelectorAll('div'))mergeArrays(...arrays)— 合并多个数组。mergeArrays([1, 2], [3, 4], [5]) // [1, 2, 3, 4, 5]flatten(arr, depth?)— 多维数组扁平化到指定层级(默认 1 层,传Infinity完全展开)。flatten([1, [2, [3, 4]], 5]) // [1, 2, [3, 4], 5] flatten([1, [2, [3, 4]], 5], Infinity) // [1, 2, 3, 4, 5]arrFind(arr, key, value)— 对象数组中按 key-value 查找第一个匹配项。arrFind([{ id: 1 }, { id: 2 }], 'id', 2) // { id: 2 }groupBy(arr, key)— 对象数组按指定属性分组。groupBy([{ type: 'fruit' }, { type: 'vegetable' }], 'type') // => { fruit: [...], vegetable: [...] }filterEmptyValues(obj)— 移除对象中值为空(null / undefined / 空字符串)的属性。filterEmptyValues({ a: 1, b: '', c: null }) // { a: 1 }createRange(length, mapFn?)— 快速生成范围数组。createRange(5) // [0, 1, 2, 3, 4] createRange(3, (i) => i * 2) // [0, 2, 4]
Cookie — cookie
setCookie(name, value, days?)— 设置 Cookie(默认7天)。setCookie('token', 'abc123', 30)getCookie(name)— 获取 Cookie。getCookie('token') // "abc123"delCookie(name)— 删除 Cookie。delCookie('token')
浏览器工具 — browser
URL 参数
getUrlParams(url?)— 获取 URL 参数对象。getUrlParams('?a=1&b=2') // { a: '1', b: '2' }getUrlParam(key, url?)— 获取单个 URL 参数。getUrlParam('a') // "1"toQueryString(params)— 对象转 URL 参数字符串。toQueryString({ a: 1, b: 'hello' }) // "a=1&b=hello"
剪贴板与文件
copyToClipboard(text)— 复制文本到剪贴板(支持降级)。await copyToClipboard('Hello')downloadFile(content, filename, mimeType?)— 下载文件(Blob)。downloadFile('Hello', 'hello.txt')exportJSON(data, filename?)— 导出 JSON 为文件。exportJSON({ name: '张三' })
页面滚动
scrollToTop(behavior?)— 滚动到顶部(默认平滑)。scrollToTop()scrollToBottom(behavior?)— 滚动到底部(默认平滑)。scrollToBottom()onScroll(callback)— 监听滚动(rAF 节流),返回清理函数。const off = onScroll(y => console.log(y))
可视区域检测
observeIntersection(target, onEnter, onLeave?, options?)— 监听元素进入/离开可视区域,返回清理函数。const cleanup = observeIntersection( document.querySelector('.footer')!, () => loadMore(10), );
防抖与节流 — control
debounce(fn, delay?, options?)— 防抖,停止调用 delay 毫秒后才执行。const fn = debounce((val: string) => console.log(val), 500) fn('a'); fn('b'); fn('c') // => 'c'throttle(fn, interval?, options?)— 节流,固定间隔内最多执行一次。const fn = throttle((val: string) => console.log(val), 500) fn('a'); fn('b'); fn('c') // => 'a',500ms 后输出 'c'
