1. 安装
npm install @xiaojinquan/super-kit
# 或
pnpm add @xiaojinquan/super-kit
- 本库将
vue 声明为可选 peerDependency,不会强制安装。
- 仅使用组件 / 指令时需要项目里存在
vue;纯工具方法(utils / env)无需 vue。
dayjs 为运行时依赖,消费方安装本包时自动拉取,不会重复打进 dist。
外部依赖说明
本库部分功能引用了外部依赖。这些依赖均不打包进 dist,以 import/require 形式保留、由消费方依赖树解析。使用前请按表确认运行环境已满足:
| 外部依赖 |
类型 |
被哪些功能引用 |
消费方是否需要安装 |
安装命令 |
dayjs |
运行时依赖(dependencies) |
utils/dateTime 全部时间函数(见 §4.7) |
否,安装本包时自动拉取 |
—(已随包安装) |
vue |
可选 peerDependency |
组件(vue3/vue2/uniapp-*)与指令(directives/vue3/directives/vue2),见 §6、§7 |
是,使用组件 / 指令时需项目自带 vue |
npm install vue |
node 内置模块(fs/path/crypto…) |
Node 运行时内置 |
node 子路径(fs / crypto / cli),见 §4.18 |
仅 Node 运行时,无需安装 |
— |
构建侧保障(防止外部依赖被误打包):
tsup.config.ts 与 scripts/vite-lib.mjs 均从 package.json 的 dependencies + peerDependencies 自动派生 external(含子路径正则),新增运行时包写进 package.json 即自动 external,无需改构建脚本。
scripts/check-external.mjs(独立命令 pnpm check:external)扫描 dist 全部产物,若发现外部依赖被内联或存在未声明依赖泄漏则非零退出;已接入 pnpm build 末尾与 pnpm publish:npm 的混淆之后,作为发布闸门。
2. 入口总览
通过 package.json 的 exports 子路径按需引入,构建工具会自动解析 ESM / CJS:
| 子路径 |
内容 |
@xiaojinquan/super-kit |
根入口 = 工具方法 + 环境解析器(importKit / detectEnv / resolveEntry / KIT_VERSION) |
@xiaojinquan/super-kit/utils |
框架无关工具方法(ESM + CJS + .d.ts) |
@xiaojinquan/super-kit/env |
环境探测 / 按环境引入解析器 |
@xiaojinquan/super-kit/node |
Node.js 专用工具(fs / crypto / cli,依赖 node 内置模块,仅 Node 运行时) |
@xiaojinquan/super-kit/vue3 |
Vue3 组件 + 指令 |
@xiaojinquan/super-kit/vue2 |
Vue2 组件 + 指令 |
@xiaojinquan/super-kit/uniapp-vue3 |
uni-app Vue3 组件 |
@xiaojinquan/super-kit/uniapp-vue2 |
uni-app Vue2 组件 |
@xiaojinquan/super-kit/directives/vue3 |
Vue3 指令(v-click-outside / v-debounce / v-copy / v-back-top / v-expand-click / v-throttle / v-water-marker / v-draggable / v-long-press) |
@xiaojinquan/super-kit/directives/vue2 |
Vue2 指令(v-click-outside / v-debounce / v-copy / v-back-top / v-expand-click / v-throttle / v-water-marker / v-draggable / v-long-press) |
@xiaojinquan/super-kit/vue3/style.css 等 |
各组件框架编译后的样式(见 §6、§7) |
3. 工具方法总览
import { formatNumber, debounce, copyText, formatDate } from "@xiaojinquan/super-kit/utils";
// 或(根入口已再导出 utils)
import { formatNumber, debounce, copyText } from "@xiaojinquan/super-kit";
全部工具方法按模块分组,均为框架无关、可 tree-shaking 的纯函数 / 类,模块之间也可互相引用(如 uniapp 依赖 parse 的 getFileUrlInfo 与 format 的 urlConversion)。
3.1 分类速查(全部导出)
| 模块 |
说明 |
全部导出 |
array |
数组处理 |
swapArrayItems sum sort unique union intersect differenceSet toArray flatten group flatToTree treeToFlat clone deepClone dataStatisticsSync dataStatistics fuzzySearch multiFieldSearch |
base |
进制 / 压缩 |
convertRadix toDecimal fromDecimal lzwCompress lzwDecompress |
calendar |
农历 / 日历(全静态方法) |
Calendar(solar2lunar / lunar2solar / toGanZhiYear / toAstro / getAnimal / getTerm / lYearDays / leapMonth / leapDays / monthDays / solarDays / toGanZhi / toChinaMonth / toChinaDay) |
canvas |
画布绘制 |
calcAngle setText drawRoundRectPath fillRoundRect textPrewrap |
chineseConverter |
简繁转换(单例) |
ChineseConverter(getInstance / toSimplified / toTraditional / toSimplifieds / toTraditionals) |
color |
颜色处理 |
rgbToHex rgbaToHex hexToRgba randomColor getGradientStyle ThemeColor |
dom |
DOM 操作 |
copyText(剪贴板复制)loadScript(加载单个外部 JS)loadScripts(顺序加载多个外部 JS)loadCSS(加载外部 CSS,同地址去重) |
dateTime |
时间处理(基于 dayjs) |
parseTime formatDate formatTimeToDateTime formatMsToDayHourMinSec isSamePeriod getTimeRange formatRelativeTime isWeekDay getDiffDays getDateRange getDaysOfPeriod isLeapYear getDayOfPeriod getWeekOfPeriod getDateRangeBetween calcExpirationDate |
device |
设备 / 系统检测(仅浏览器) |
getSystem(基于 navigator.userAgent 识别 iOS / Android / HarmonyOS / 桌面)browserType(基于 navigator.userAgent 识别 IE / Edge / Firefox / Opera / Safari / Chrome)isWechat(是否处于微信内置浏览器)getWechatVersion(微信版本号,如 "7.0.21",非微信返回 null) |
desensitize |
脱敏 |
maskString desensitizePhone desensitizeEmail desensitizeIdCard desensitizeName desensitizeBankCard desensitizePhoneLandline |
format |
格式化 |
formatFileSize formatPercent formatPhone formatBankCard formatIdCard formatDecimal formatNumberShort formatNumber formatCompact parseNumber truncateDecimal roundDecimal formatDistance numberToChinese amountToChinese urlConversion |
function |
函数增强 |
debounce throttle throttleTimer |
http |
网络请求 |
ajax(XHR Promise 化)+ AjaxError(错误分类:network/timeout/abort/http/parse)+ fetchHttp(fetch 封装)。readFileContent 已移入 file(本质是「GET 文本 + 可选 \uXXXX 解码」,归属资源读取语义),decodeUnicodeEscapes 已移入 string(纯字符串工具)。 |
file |
文件 / 图像 / 媒体处理(仅浏览器) |
imageToBase64(URL → base64 dataURL)base64ImgDownloadFile(dataURL → 下载)dataUrlToBlob(dataURL → Blob,Node v16+ 亦可)downloadBlob(Blob / 文件流 → 下载)downloadTable(对象数组 → TSV / CSV)loadAudio(音频加载 → 可播放 HTMLAudioElement)captureFrame(视频 → 截帧,正确的 loadedmetadata → currentTime → seeked 流程)readFileContent(GET 文本读取 + 可选 \uXXXX 解码,依赖 http/fetchHttp + string/decodeUnicodeEscapes,自 http 模块移入) |
location |
经纬度(全静态方法) |
Location(getDistance / getDistanceVincenty / polymerization / getLocationCenter / gcj02towgs84 / wgs84togcj02 / bd09togcj02 / gcj02tobd09 / getPolygonArea / isPointInPolygon) |
parse |
解析 |
getInfoByIdCard getPasswordStrength getFileUrlInfo extractRichText |
random |
随机 |
generateCaptcha randomInt randomFloat randomIntExclude randomPick shuffle randomBoolean uuidv4 |
string |
字符串 |
escapeHtml unescapeHtml zeroWidthTrim byteLength camelToSeparated separatedToCamel queryString queryObject trim convertCase decodeUnicodeEscapes(自原 http 模块移入,解码 \uXXXX 转义;命名如实反映行为) |
storage |
浏览器存储(cookie / localStorage / sessionStorage) |
setCookie getCookie getCookies setCookies removeCookie clearCookies setLocalStorage getLocalStorage getAllLocalStorage getLocalStorageKeys removeLocalStorage clearLocalStorage setSessionStorage getSessionStorage getAllSessionStorage getSessionStorageKeys removeSessionStorage clearSessionStorage LocalStorageWatcher localStorageWatcher SessionStorageWatcher sessionStorageWatcher CookieWatcher cookieWatcher |
validator |
校验 |
isString isNumber isBoolean isFunction isNull isUndefined isNil isPlainObject isArray isDate isRegExp isError isSymbol isPromise isSet isFile isBlob isFalse isTrue isEmpty isNotBlank isCamelCase isHasZeroWidthChars isSeparated isValidIdCard Validator 类 |
uniapp |
uni-app / 小程序 API 封装 |
showToast chooseMessageFile chooseMedia previewMedia downloadFile openDocument filePreviewShare saveImageToPhotosAlbum chooseLocation getLocation updateApplet addPhoneContact getLoginCode getScreenBrightness getDomInfo getImageInfo getSystemInfoSync rpxToPx pxToRpx backRefresh storageWatcher(StorageWatcher 全局唯一单例,可监听本地缓存事件中心) |
node/fs |
文件系统(仅 Node) |
ensureDir readJsonFile readJsonFileSync writeJsonFile writeJsonFileSync tempFilePath(引用 utils.uuidv4) |
node/crypto |
哈希 / 令牌(仅 Node) |
md5 sha256 randomHex randomToken uuidv4(再导出 utils) |
node/cli |
命令行解析(仅 Node) |
parseArgs formatArgHelp generateRunId(引用 utils.uuidv4) |
4. 各模块完整 API 参考
4.1 array — 数组处理
| 函数 |
签名 |
说明 |
swapArrayItems |
<T>(arr: T[], index1: number, index2: number, options?: SwapOptions): T[] |
交换两个位置元素。options.mutate 默认 false(返回新数组);options.throwOnInvalid 默认 false(越界时返回原数组并告警) |
sum |
<T>(data: T[], key?: keyof T): number |
求和;传入 key 则对对象该属性求和,自动过滤非数值 |
sort |
<T>(data: T[], key?: keyof T, order?: SortOrder): T[] |
排序,order 为 'asc' | 'desc',默认 'asc',不修改原数组 |
unique |
<T>(arr: T[], key?: keyof T): T[] |
去重;传 key 按对象属性去重 |
union |
<T>(a: T[], b: T[]): T[] |
并集(去重) |
intersect |
<T>(a: T[], b: T[]): T[] |
交集 |
differenceSet |
<T>(arrOne: T[], arrTwo: T[]): T[] |
对称差集 |
toArray |
<T>(arrayLike: ArrayLike<T> | Iterable<T>): T[] |
类数组 / 可迭代对象转真数组 |
flatten |
(arr: any[], depth?: number): T[] |
扁平化,depth 默认 Infinity |
group |
<T extends Record<string, any>>(arr: T[], key: keyof T): GroupResult<T>[] |
按属性分组,返回 [{ name, children }] |
flatToTree |
<T extends Record<string, any>>(data: T[], relation?: [string,string], children?: string, hasChildren?: string): T[] |
平铺数组转树形,relation 默认 ['pid','id'] |
treeToFlat |
<T extends Record<string, any>>(data: T[], relation?: [string,string], children?: string, hasChildren?: string): T[] |
树形转平铺数组 |
clone |
<T>(target: T): T |
浅拷贝(数组 / 对象一层) |
deepClone |
<T>(value: T, cache?: Map<any,any>): T |
深拷贝,支持循环引用、Date / RegExp |
dataStatisticsSync |
<T>(array: T[], generateKey: (item: T) => string | number | symbol | null | undefined): StatisticsResult |
同步分组计数,返回 { [key]: count } |
dataStatistics |
<T>(array: T[], generateKey: (item: T) => ... | Promise<...>): Promise<StatisticsResult> |
异步版,generateKey 可返回 Promise |
fuzzySearch |
(str: unknown, pattern: string, options?: FuzzySearchOptions): boolean |
SQL LIKE 模糊匹配(% 任意多字符、_ 单字符);options.caseSensitive / exactMatch 默认 false |
multiFieldSearch |
<T extends Record<string, any>>(array: T[], fields: (keyof T)[], pattern: string, options?: MultiFieldSearchOptions): T[] |
多字段模糊查询;options.matchAllFields 默认 false、fieldMissing 默认 'skip' |
import {
unique,
flatten,
group,
flatToTree,
treeToFlat,
deepClone,
fuzzySearch,
} from "@xiaojinquan/super-kit/utils";
unique([1, 1, 2, 3]); // [1, 2, 3]
flatten([1, [2, [3]]]); // [1, 2, 3]
group([{ t: "A" }, { t: "A" }], "t"); // [{ name: 'A', children: [...] }]
flatToTree(list, ["pid", "id"]); // 树形数组
treeToFlat(tree, ["pid", "id"], "children");
deepClone(obj); // 深拷贝(带循环引用缓存)
fuzzySearch("hello", "h%o"); // true
4.2 base — 进制 / 压缩
| 函数 |
签名 |
说明 |
convertRadix |
(num: string | number, fromRadix?: Radix, toRadix?: Radix, options?: RadixConvertOptions): string |
2–36 进制互转;options.useBigInt / allowPrefix(默认 true,识别 0x/0b/0o)/ outputPrefix |
toDecimal |
(num: string, fromRadix?: Radix): number |
指定进制字符串转十进制数字 |
fromDecimal |
(num: number | string, toRadix?: Radix): string |
数字转指定进制字符串(BigInt,避免精度丢失) |
lzwCompress |
(input: string, options?: LzwOptions): string |
LZW 压缩;options.maxDictSize 默认 4096、outputBase64 默认 false |
lzwDecompress |
(input: string, options?: LzwOptions): string |
LZW 解压;options.autoDetectBase64 默认 true |
import {
convertRadix,
toDecimal,
fromDecimal,
lzwCompress,
lzwDecompress,
} from "@xiaojinquan/super-kit/utils";
convertRadix("110", 2, 10); // '6'
convertRadix("AF", 16, 10); // '175'
convertRadix("175", 10, 16); // 'af'
toDecimal("ff", 16); // 255
fromDecimal(255, 16); // 'ff'
lzwCompress("repeat repeat"); // 压缩字符串(可 outputBase64: true)
lzwDecompress(compressed); // 还原
4.3 calendar — 农历 / 日历(全静态方法,无需实例化)
import { Calendar } from "@xiaojinquan/super-kit/utils";
| 静态方法 |
签名 |
返回 |
说明 |
solar2lunar |
(y?: number, m?: number, d?: number): LunarResult | -1 |
农历信息对象 |
公历 → 农历;不传参取当天;非法返回 -1 |
lunar2solar |
(y: number, m: number, d: number, isLeapMonth?: boolean): LunarResult | -1 |
农历信息对象 |
农历 → 公历;非法返回 -1 |
toGanZhiYear |
(lYear: number): string |
干支纪年,如 '甲辰' |
|
toAstro |
(cMonth: number, cDay: number): string |
星座,如 '摩羯座' |
|
toGanZhi |
(offset: number): string |
干支(按偏移) |
|
getTerm |
(y: number, n: number): number |
第 n 个节气(公历日),n:1–24 |
|
toChinaMonth |
(m: number): string | number |
农历月中文,如 '正月' |
|
toChinaDay |
(d: number): string |
农历日中文,如 '廿一' |
|
getAnimal |
(y: number): string |
生肖,如 '龙' |
|
lYearDays |
(y: number): number |
农历某年总天数 |
|
leapMonth |
(y: number): number |
闰月月份,无则返回 0 |
|
leapDays |
(y: number): number |
闰月天数 |
|
monthDays |
(y: number, m: number): number |
农历某月天数 |
|
solarDays |
(y: number, m: number): number |
公历某月天数 |
|
LunarResult 含:lYear lMonth lDay Animal IMonthCn IDayCn cYear cMonth cDay gzYear gzMonth gzDay isToday isLeap nWeek ncWeek isTerm Term astro。
Calendar.solar2lunar(2026, 1, 1); // { lYear: 2025, IMonthCn: '腊月', ... }
Calendar.lunar2solar(2026, 1, 1); // 公历信息对象
Calendar.toGanZhiYear(2026); // '丙午'
Calendar.getAnimal(2026); // '马'
4.4 canvas — 画布绘制(传入 CanvasRenderingContext2D)
| 函数 |
签名 |
说明 |
calcAngle |
(angle: number, width: number, height: number, startX?: number, startY?: number): [number, number, number, number] |
计算沿角度方向的线性渐变起止坐标 [x0,y0,x1,y1] |
setText |
(ctx, color?, font?, textAlign?, textBaseline?): void |
设置文本样式(默认 #999999 / 38px PingFangSC-Medium, PingFang SC / left / top) |
drawRoundRectPath |
(ctx, width: number, height: number, radius?: number): void |
仅构建圆角矩形路径(不填充) |
fillRoundRect |
(ctx, x, y, width, height, radius?, fillColor?): void |
绘制并填充圆角矩形(自动 save/restore) |
textPrewrap |
(ctx, content, drawX, drawY, fontSize, lineHeight, lineMaxWidth, lineNum, indent?): void |
自动换行绘制文本,lineNum 超出截断加 ... |
import { textPrewrap, fillRoundRect, drawRoundRectPath } from "@xiaojinquan/super-kit/utils";
const ctx = canvas.getContext("2d")!;
fillRoundRect(ctx, 10, 10, 200, 100, 15, "rgba(0,150,255,0.8)");
textPrewrap(ctx, "长文本…", 10, 10, 16, 24, 200, 3, 20);
4.5 chineseConverter — 简繁转换(单例)
import { ChineseConverter } from "@xiaojinquan/super-kit/utils";
const cv = ChineseConverter.getInstance(); // 全局唯一实例
| 方法 |
签名 |
说明 |
getInstance |
(): ChineseConverter |
获取单例 |
toSimplified |
(char: string): string |
单个繁体字 → 简体(非单字返回 '') |
toTraditional |
(char: string): string |
单个简体字 → 繁体 |
toSimplifieds |
(str: string): string |
繁体字符串 → 简体 |
toTraditionals |
(str: string): string |
简体字符串 → 繁体 |
ChineseConverter.getInstance().toSimplifieds("繁體"); // '繁体'
ChineseConverter.getInstance().toTraditionals("简体"); // '簡體'
4.6 color — 颜色处理
| 函数 |
签名 |
返回 / 说明 |
rgbToHex |
(r: number|string, g: number|string, b: number|string): HexColor |
如 '#ff0000',越界自动裁剪 |
rgbaToHex |
(r, g, b, a?, bgR?, bgG?, bgB?): HexColor |
半透明叠加背景色后转不透明 hex(默认白底) |
hexToRgba |
(hex: string, alpha?: number, asString?: boolean): RGBA | string | null |
支持 #rgb/#rrggbb;asString 返回 'rgba(...)';非法返回 null |
randomColor |
(options?: RandomColorOptions): string |
options.format(hex/rgb/rgba/hsl)、alpha、brightness(light/dark/any) |
getGradientStyle |
(str: string, params?: GradientStyleParams): GradientStyleResult |
按字符串稳定哈希生成渐变样式;相同字符串恒定同色。可配 angle/type(linear/radial)/radialShape(circle/ellipse)/gradients;返回含 style.backgroundImage、所选 index 与归一化配置 |
ThemeColor |
new ThemeColor(imgUrl, callBack?, options?): ThemeColor |
浏览器 / H5 专用:从图片提取出现次数最多的主色调。结果经回调或 await themeColor.ready 获取({ shrinkUrl, themeColor, rgba });跨域图片需 CORS 头;失败回退白色 |
import { rgbToHex, rgbaToHex, hexToRgba, randomColor, getGradientStyle, ThemeColor } from "@xiaojinquan/super-kit/utils";
rgbToHex(255, 0, 0); // '#ff0000'
rgbaToHex(255, 0, 0, 0.5); // '#ff8080'
hexToRgba("#ff0000"); // { r:255, g:0, b:0, a:1 }
hexToRgba("#ff0000", 0.5, true); // 'rgba(255,0,0,0.5)'
randomColor({ format: "hex", brightness: "light" });
// 文字渐变:相同字符串恒定同一渐变
const g = getGradientStyle("Hello World");
// <span style={g.style}>Hello World</span>
getGradientStyle("Custom", { angle: 90, type: "radial", radialShape: "circle" });
// 图片主色提取(浏览器 / H5)
const tc = new ThemeColor("https://example.com/cover.jpg");
const { shrinkUrl, themeColor, rgba } = await tc.ready;
4.7 dateTime — 时间处理(基于 dayjs)
⚠️ 依赖 dayjs:本模块全部时间函数基于 dayjs 及其 weekOfYear / dayOfYear 插件实现。dayjs 为运行时依赖(已写入 package.json 的 dependencies),安装本包时自动拉取,无需另行安装。
| 函数 |
签名 |
说明 |
parseTime |
(time: TimeInput): Dayjs | null |
解析时间,无效返回 null |
formatDate |
(time: TimeInput, formatStr?: string): string |
默认 'YYYY-MM-DD HH:mm:ss',无效返回 '' |
formatTimeToDateTime |
(time: TimeInput): string |
同年省略年份,跨年显示完整;同日带 HH:mm |
formatMsToDayHourMinSec |
(ms: number): string |
1天2时3分4秒;负数 / NaN 返回 '' |
isSamePeriod |
(time1, time2, unit: PeriodUnit): boolean |
day/week/month/year 是否同期 |
getTimeRange |
(unit: PeriodUnit, time?: TimeInput, weekStartsOn?: WeekStartDay): [number, number] |
时段起止时间戳 [startMs, endMs];weekStartsOn:0=周日,1=周一 |
formatRelativeTime |
(time: TimeInput, baseTime?): string |
中文相对时间(刚刚 / 分钟前 / 昨天 / X天前 / X个月前 / X年前;未来时间返回日期) |
isWeekDay |
(time: TimeInput): boolean |
是否工作日(周一至周五) |
getDiffDays |
(time1, time2): number |
相差天数(绝对值向下取整) |
getDateRange |
(unit: PeriodUnit, time: TimeInput, len?: number, direction?: 1|2|3): string[] |
前后日期数组;direction:1前 2后 3前后含基准 |
getDaysOfPeriod |
(unit: MonthYearUnit, time?): number |
当月 / 当年天数 |
isLeapYear |
(year: YearInput): boolean |
是否闰年 |
getDayOfPeriod |
(unit: WeekMonthYearUnit, time?): number |
当年第几天 / 第几月 / 第几周 |
getWeekOfPeriod |
(unit: MonthYearUnit, time?): number |
该月 / 该年第几周 |
getDateRangeBetween |
(unit: PeriodUnit, time1, time2): DateRangeItem[] |
两日期间按单位划分的时间点数组 [{ timestamp, label }] |
calcExpirationDate |
(startTime: TimeInput, years, months, days): number |
截止日期时间戳;负数参数返回 0 |
import {
formatDate,
formatRelativeTime,
getTimeRange,
isLeapYear,
} from "@xiaojinquan/super-kit/utils";
formatDate(1735689600000); // '2026-01-01 00:00:00'
formatDate("2026-08-20", "YYYY-MM-DD"); // '2026-08-20'
formatRelativeTime("2026-08-19 12:00", "2026-08-20 12:00"); // '昨天'
const [start, end] = getTimeRange("month"); // 本月起止时间戳
isLeapYear(2024); // true
4.8 desensitize — 脱敏
| 函数 |
签名 |
说明 |
maskString |
(str: StringInput, start?: number, end?: number, mask?: string, maskLen?: number): string |
通用脱敏,保留前 start、后 end 位 |
desensitizePhone |
(phone): string |
手机号:138****5678(前3后4) |
desensitizeEmail |
(email): string |
邮箱:本地保留首字符,如 t***@example.com |
desensitizeIdCard |
(id): string |
身份证:前6后4,110101********1234 |
desensitizeName |
(name): string |
姓名:张** / 张*三 |
desensitizeBankCard |
(card): string |
银行卡:前4后4 |
desensitizePhoneLandline |
(phone): string |
固定电话:保留后4位,区号不脱敏 |
import {
desensitizePhone,
desensitizeName,
desensitizeIdCard,
} from "@xiaojinquan/super-kit/utils";
desensitizePhone("13812345678"); // '138****5678'
desensitizeName("张三"); // '张**'
desensitizeIdCard("110101199001011234"); // '110101********1234'
4.9 dom — DOM 操作
| 函数 |
签名 |
说明 |
copyText |
(text: string): Promise<boolean> |
复制文本到剪贴板;优先 navigator.clipboard,降级 execCommand('copy');返回是否成功 |
loadScript |
(url: string, callback?: () => void): Promise<void> |
动态加载单个外部 JS(注入 <script> 到 <head>);加载成功 resolve、失败 reject;兼容回调式用法 |
loadScripts |
(urls: string[], callback?: () => void): Promise<void> |
顺序加载多个外部 JS(前完成再加载下一个);全部完成 resolve、任一失败 reject;兼容回调式用法 |
loadCSS |
(url: string, options?: LoadCssOptions): Promise<void> |
动态加载外部 CSS(注入 <link rel="stylesheet">);同地址自动去重;options.media 支持媒体查询 |
import { copyText, loadScript, loadScripts, loadCSS } from "@xiaojinquan/super-kit/utils";
const ok = await copyText("hello");
if (ok) console.log("已复制");
// 指令 v-copy 内部即调用 copyText
await loadScript("/sdk.js"); // 推荐:Promise 式
loadScript("/sdk.js", () => console.log("loaded")); // 兼容:回调式
await loadScripts(["/a.js", "/b.js", "/c.js"]); // 依次加载 a → b → c
await loadCSS("/theme.css");
await loadCSS("/print.css", { media: "print" });
4.10 format — 格式化
| 函数 |
签名 |
说明 |
formatFileSize |
(bytes: NumericInput, decimals?: number): string |
1.23 MB;0 → '0 B' |
formatPercent |
(num: NumericInput, decimals?, includeSign?): string |
12.34%(0.1234 → 12.34%) |
formatPhone |
(phone: NumericInput, separator?: string): string |
138-1234-5678 |
formatBankCard |
(card: NumericInput, separator?): string |
每4位一组,6222 0000 1234 5678 |
formatIdCard |
(id: NumericInput, separator?): string |
110101 19900307 1234 |
formatDecimal |
(num: NumericInput, decimals?): string |
保留小数(不补千分位) |
formatNumberShort |
(num: NumericString): string |
<10万 原样,k / w 单位缩写 |
formatNumber |
(num: unknown, options?: FormatNumberOptions): string |
千分位格式化;options:decimals/forceDecimals/thousandsSeparator/decimalSeparator/currency/currencyPosition/negativeFormat |
formatCompact |
(num: unknown, decimals?): string |
紧凑显示 1.2k / 3.5M / 987.7M |
parseNumber |
(str: unknown, options?: ParseNumberOptions): number |
解析格式化字符串为数字;非法返回 NaN;options.thousandsSeparator/decimalSeparator |
truncateDecimal |
(num: number, fixed?): number |
截断(非四舍五入) |
roundDecimal |
(num: number, fixed?): number |
四舍五入 |
formatDistance |
(meters: unknown, options?: DistanceFormatOptions): string |
米 / 公里自适应;options:unit/nearThreshold/prefix/suffix/decimals/showUnit |
numberToChinese |
(num: unknown, options?: ChineseNumberOptions): string |
数字转中文;options.style(lower/upper)、useUnits/handleDecimal/simplifyTen |
amountToChinese |
(amount: unknown, options?: CurrencyChineseOptions): string |
金额转中文大写;options.includeWhole/negativePrefix |
urlConversion |
(path: string): string |
http://→https://、自动补 // 协议、已是 https 原样返回 |
import {
formatNumber,
amountToChinese,
urlConversion,
formatPhone,
numberToChinese,
} from "@xiaojinquan/super-kit/utils";
formatNumber(1234567.89); // '1,234,567.89'
formatNumber(1234567.89, { currency: "¥" }); // '¥1,234,567.89'
amountToChinese(1234.56); // '壹仟贰佰叁拾肆元伍角陆分'
urlConversion("//a.com/b"); // 'https://a.com/b'
formatPhone("13812345678"); // '138-1234-5678'
numberToChinese(1234); // '一千二百三十四'
4.11 function — 函数增强
| 函数 |
签名 |
说明 |
debounce |
<T extends Fn>(func: T, delay: number): DebouncedFunction<T> |
防抖(最后一次触发后延迟执行);返回函数带 .cancel() |
throttle |
<T extends Fn>(func: T, interval: number): DebouncedFunction<T> |
时间戳节流(首次立即执行);.cancel() 仅为接口一致 |
throttleTimer |
<T extends Fn>(func: T, interval: number): DebouncedFunction<T> |
定时器节流(首次延迟、末次执行);.cancel() 可取消待执行任务 |
import { debounce, throttle, throttleTimer } from "@xiaojinquan/super-kit/utils";
const search = debounce((v: string) => console.log(v), 300);
search.cancel(); // 取消待执行任务
const scroll = throttle(() => {}, 200);
const click = throttleTimer(() => {}, 1000);
4.12 location — 经纬度(全静态方法,无需实例化)
import { Location } from "@xiaojinquan/super-kit/utils";
| 静态方法 |
签名 |
说明 |
getDistance |
(lng1, lat1, lng2, lat2): number |
两点球面距离(米,Haversine) |
getDistanceVincenty |
(lng1, lat1, lng2, lat2): number |
Vincenty 测地线距离(更精确,不收敛回退 Haversine) |
polymerization |
<T extends Point>(data: T[], threshold?: number): T[][] |
坐标聚合(并查集),threshold 默认 100 米 |
getLocationCenter |
<T extends Point>(points: T[]): T | null |
多边形中心点(平均坐标) |
gcj02towgs84 |
(lng, lat): Point |
GCJ-02(火星)→ WGS-84 |
wgs84togcj02 |
(lng, lat): Point |
WGS-84 → GCJ-02 |
bd09togcj02 |
(bdLon, bdLat): Point |
BD-09(百度)→ GCJ-02 |
gcj02tobd09 |
(lng, lat): Point |
GCJ-02 → BD-09 |
getPolygonArea |
(points: Point[]): number |
多边形面积(平方米) |
isPointInPolygon |
(point: Point, polygon: Point[]): boolean |
射线法判断点是否在多边形内 |
Point = { longitude: number; latitude: number }。
Location.getDistance(116.4, 39.9, 121.47, 31.23); // 两点球面距离(米)
Location.wgs84togcj02(116.4, 39.9); // 坐标转换
4.13 parse — 解析
| 函数 |
签名 |
返回 |
说明 |
getInfoByIdCard |
(idCard: unknown): IdCardInfo | null |
{ birthday, gender, age } |
解析 18 位身份证;非法返回 null |
getPasswordStrength |
(password: unknown, minLength?: number, specialChars?: RegExp): PasswordStrengthResult |
{ level, description, score, length, meetsMinLength } |
密码强度(数字/小写/大写/特殊各 1 分) |
getFileUrlInfo |
(url: string): FileUrlInfo | undefined |
{ fullName, name, suffix, type } |
从 URL 提取文件信息;type:1图 2视频 3文档 4音频;不支持返回 undefined |
extractRichText |
(html: string, options?: ExtractOptions): RichTextExtractResult |
{ text, images, videos, audios, iframes, links, otherMedia } |
富文本提取纯文本与媒体 URL;options 可逐项开关提取 |
import {
getInfoByIdCard,
getPasswordStrength,
getFileUrlInfo,
extractRichText,
} from "@xiaojinquan/super-kit/utils";
getInfoByIdCard("110101199003071234"); // { birthday:'1990-03-07', gender:'男', age:36 }
getPasswordStrength("Abc123_"); // { level:4, description:'极强', score:4, length:7, meetsMinLength:true }
getFileUrlInfo("https://x/y.jpg"); // { fullName:'y.jpg', name:'y', suffix:'jpg', type:'1' }
4.14 random — 随机
| 函数 |
签名 |
说明 |
generateCaptcha |
(digit?: number, options?: GenerateCaptchaOptions): string |
验证码;digit 默认 6;options.charSet(number/letter/alphanumeric)、case(upper/lower/mixed)、excludeAmbiguous 默认 true |
randomInt |
(a: number, b?: number, options?: RandomOptions): number |
随机整数;单参 [0,a];options.inclusive 默认 true、validateRange 默认 true(自动交换 min/max) |
randomFloat |
(a: number, b?: number): number |
随机浮点;单参 [0,a] |
randomIntExclude |
(min: number, max: number, exclude: number[]): number |
排除指定数字的随机整数(递归重取) |
randomPick |
<T>(arr: T[]): T | undefined |
随机取一个元素 |
shuffle |
<T>(arr: T[]): T[] |
Fisher-Yates 洗牌(返回新数组) |
randomBoolean |
(probability?: number): boolean |
true 概率,默认 0.5 |
uuidv4 |
(): string |
UUID v4(优先 crypto.randomUUID()) |
import { uuidv4, randomInt, generateCaptcha, shuffle } from "@xiaojinquan/super-kit/utils";
uuidv4(); // '3b1f8c7e-2a9d-4c5b-...'
randomInt(1, 10); // 1~10
generateCaptcha(6, { charSet: "number" }); // '372915'
shuffle([1, 2, 3, 4, 5]);
4.15 string — 字符串
| 函数 |
签名 |
说明 |
escapeHtml |
(str: unknown, options?: EscapeHtmlOptions): unknown |
HTML 转义;options.escapeSpace/escapeDoubleQuote(默认 true)/escapeSingleQuote |
unescapeHtml |
(str: unknown): unknown |
HTML 反转义 |
zeroWidthTrim |
(str: unknown, options?: ZeroWidthOptions): unknown |
移除零宽字符;options.customRegex/debug |
byteLength |
(str: unknown): number |
UTF-8 字节长度(中文 3、emoji 4) |
camelToSeparated |
(str: unknown, separator?: string): unknown |
驼峰 → 分隔符(camelCase→camel_case) |
separatedToCamel |
(str: unknown, separator?, capitalizeFirst?): unknown |
分隔符 → 驼峰;capitalizeFirst 默认 false(大驼峰) |
queryString |
(obj: Record<string, any>): string |
对象 → 查询串(过滤 null/undefined,支持数组) |
queryObject |
(str: string): Record<string, string> |
查询串 → 对象(重复键取后者) |
trim |
(str: unknown, mode?: TrimMode): unknown |
mode: 'all'/'start'/'end'/'extra'(合并多余空格)/'both'(默认) |
convertCase |
(str: unknown, mode?: CaseMode): unknown |
mode: 'upper'(默认)/'lower'/'capitalize'/'uncapitalize'/'swap' |
decodeUnicodeEscapes |
(input: string): string |
解码 \uXXXX 转义序列(自原 http 模块移入);用显式正则 + String.fromCharCode,无废弃 unescape |
import {
escapeHtml,
camelToSeparated,
queryObject,
trim,
convertCase,
decodeUnicodeEscapes,
} from "@xiaojinquan/super-kit/utils";
escapeHtml("<a>"); // '<a>'
camelToSeparated("fooBar"); // 'foo_bar'
queryObject("?a=1&b=2"); // { a:'1', b:'2' }
trim(" a b ", "extra"); // 'a b'
convertCase("hello world", "capitalize"); // 'Hello World'
decodeUnicodeEscapes("\\u4F60\\u597D"); // '你好'
4.16 storage — 浏览器存储(cookie / localStorage / sessionStorage)
仅浏览器 / H5 可用(依赖 DOM document / window.localStorage / window.sessionStorage);Node / uni-app 小程序原生端不可用。cookie 读写的编解码复用 string 模块的 queryObject(解析 document.cookie),与 queryString 风格一致。提供三个可监听缓存类(API 风格一致,互相对称):
LocalStorageWatcher — 监听 localStorage(支持跨标签页同步,原生 storage 事件)
SessionStorageWatcher — 监听 sessionStorage(仅同标签页,无原生事件)
CookieWatcher — 监听 cookie(基于轮询 diff,默认 500ms,能捕获任意来源写入)
| 函数 / 类 |
签名 |
说明 |
setCookie |
(name: string, value: string, options?: CookieOptions): void |
设置单个 cookie(值自动 encode);options:expires(天)/maxAge(秒)/path/domain/secure/sameSite |
setCookies |
(cookies: Record<string, string>, options?: CookieOptions): void |
批量设置 cookie(统一 options) |
getCookie |
(name: string): string |
读单个 cookie(值自动 decode);未命中返回 "" |
getCookies |
(): Record<string, string> |
读全部 cookie(复用 queryObject) |
removeCookie |
(name: string, options?: CookieOptions): void |
删除单个 cookie(max-age=-1) |
clearCookies |
(): void |
清空全部 cookie |
setLocalStorage |
(key: string, value: unknown): void |
写 localStorage(JSON.stringify) |
getLocalStorage |
<T>(key: string): T | null |
读 localStorage(JSON.parse,失败/缺失返回 null) |
getAllLocalStorage |
(): Record<string, unknown> |
读全部 localStorage |
getLocalStorageKeys |
(): string[] |
读 localStorage 全部 key |
removeLocalStorage |
(key: string): void |
删 localStorage 指定 key |
clearLocalStorage |
(): void |
清空 localStorage |
setSessionStorage |
(key: string, value: unknown): void |
写 sessionStorage(JSON.stringify) |
getSessionStorage |
<T>(key: string): T | null |
读 sessionStorage |
getAllSessionStorage |
(): Record<string, unknown> |
读全部 sessionStorage |
getSessionStorageKeys |
(): string[] |
读 sessionStorage 全部 key |
removeSessionStorage |
(key: string): void |
删 sessionStorage 指定 key |
clearSessionStorage |
(): void |
清空 sessionStorage |
LocalStorageWatcher |
new LocalStorageWatcher(storage?: Storage) |
可监听 localStorage;构造可传任意 Storage 实例;跨标签页通过原生 storage 事件同步;同标签页由 setStorageWatch/removeStorageWatch/clearStorageWatch 触发;提供 watchStorage/unWatchStorage/hasPendingEvent/destroy |
localStorageWatcher |
LocalStorageWatcher |
全局唯一单例(推荐直接 import 使用) |
SessionStorageWatcher |
new SessionStorageWatcher(storage?: Storage) |
可监听 sessionStorage;不支持跨标签页(storage 事件仅对 localStorage 触发);同标签页由内部桥接函数触发;方法签名与 LocalStorageWatcher 一致 |
sessionStorageWatcher |
SessionStorageWatcher |
全局唯一单例(推荐直接 import 使用) |
CookieWatcher |
new CookieWatcher(options?: CookieWatcherOptions) |
可监听 cookie;基于轮询 diff(默认 500ms,最小 50ms);能捕获任意来源写入(直接 JS / Set-Cookie 响应头 / 第三方脚本);不提供 setCookieWatch 等桥接函数;提供 watchCookie/unWatchCookie/pause/resume/isRunning/hasPendingEvent/destroy |
cookieWatcher |
CookieWatcherSingleton(懒加载) |
全局单例;仅在首次 watchCookie 时才启动轮询定时器——若业务侧从未调用 watchCookie,不会产生任何轮询开销 |
import {
setCookie, getCookie, getCookies,
setLocalStorage, getLocalStorage,
setSessionStorage, getSessionStorage,
LocalStorageWatcher, localStorageWatcher,
SessionStorageWatcher, sessionStorageWatcher,
CookieWatcher, cookieWatcher,
} from "@xiaojinquan/super-kit/utils";
// cookie
setCookie("token", "abc", { expires: 7, sameSite: "Lax" });
getCookie("token"); // 'abc'
getCookies(); // { token: 'abc', ... }
// localStorage / sessionStorage(自动 JSON 序列化 / 反序列化)
setLocalStorage("user", { id: 1, name: "Tom" });
getLocalStorage("user"); // { id: 1, name: 'Tom' }
setSessionStorage("draft", { text: "hello" });
getSessionStorage("draft"); // { text: 'hello' }
// LocalStorageWatcher:跨标签页同步 + 同标签页桥接
const off = localStorageWatcher.watchStorage("token", (newVal, oldVal) => {
console.log(newVal, oldVal);
});
localStorageWatcher.setStorageWatch("token", "abc123"); // 触发上面的回调
off(); // 取消监听
// SessionStorageWatcher:仅同标签页同步
sessionStorageWatcher.watchStorage("draft", (newVal) => console.log(newVal));
sessionStorageWatcher.setStorageWatch("draft", { title: "未命名" });
// CookieWatcher:轮询 diff(≤500ms 内触发)
cookieWatcher.watchCookie("token", (newVal, oldVal) => {
console.log("token 变化:", newVal, oldVal);
});
setCookie("token", "new-value"); // 下一个 tick 内触发回调
// 自定义轮询间隔
const cw = new CookieWatcher({ intervalMs: 1000 });
4.17 uniapp — uni-app / 小程序 API 封装
对 uni.* 回调式 API 做 Promise 化 / 对象传参 / 字段对齐官方命名 封装,不依赖 @dcloudio/uni-app 类型包(内部维护局部 Uni 子集类型 + getUni() 运行时访问,非 uni 环境抛明确错误)。入参均为对象、字段一一对应官方命名;文件类方法支持 [key: string]: unknown 透传索引签名(官方新增字段无需改库)。
| 函数 |
签名 |
说明 |
showToast |
(params?: string | ShowToastOptions): void |
轻提示;字符串或对象传参;默认 icon:'none';先 hideLoading() 再延迟 100ms 显示 |
chooseMessageFile |
(params?: Partial<ChooseMessageFileOptions>): Promise<ChooseMessageFileResult | false> |
聊天选文件;count 钳制 1–9;失败 resolve(false) |
chooseMedia |
(params?: Partial<ChooseMediaOptions>): Promise<ChooseMediaResult | false> |
选媒体;count 钳制 1–9、默认 mediaType:['image','video'];失败 resolve(false) |
scanCode |
(params?: ScanCodeOptions): Promise<ScanCodeResult | false> |
扫码;scanType 默认 ['qrCode','barCode'](二维码+一维码);经 getUni() 调用,失败(含取消)resolve(false) |
previewMedia |
(params?: Partial<PreviewMediaParams>): void |
图片/视频预览;按 URL 后缀自动推断 type,无效资源过滤 |
downloadFile |
(params: DownloadFileParams): Promise<string | false> |
下载;url 经 urlConversion 转 https;fileName 自动拼 USER_DATA_PATH;失败 resolve(false) |
openDocument |
(params: OpenDocumentParams): Promise<boolean> |
打开文档;filePath 必填;失败 resolve(false) |
filePreviewShare |
(fileName?, downloadParams?, openParams?): void |
组合封装:下载 → 打开文档 |
saveImageToPhotosAlbum |
(filePath?, options?: SaveImageOptions): void |
存图到相册;options.mode:'direct'(默认)/'authorize';权限拒绝引导去设置 |
chooseLocation |
(params?: ChooseLocationOptions): Promise<ChooseLocationResult | false> |
打开地图选位置;mode 同上(默认 'direct');checkSystem(默认 true)预检系统定位开关;失败 resolve(false) |
getLocation |
(params?: GetLocationOptions): Promise<GetLocationResult | false> |
获取当前坐标;与 chooseLocation 同构的 scope.userLocation 授权 + mode + checkSystem,无 UI;失败 resolve(false) |
updateApplet |
(): void |
检查小程序更新(getUpdateManager 封装) |
addPhoneContact |
(params?: AddPhoneContactParams): Promise<boolean> |
存联系人;getSetting 权限检查 + authorize/引导设置;字段对齐官方命名;成功 resolve(true) / 失败 resolve(false) |
getLoginCode |
(params?: GetLoginCodeParams): Promise<string | false> |
登录 code;provider 缺省时经 getProvider({service:'oauth'}) 动态获取(优先 weixin);失败 resolve(false) |
getScreenBrightness |
(params?: GetScreenBrightnessParams): Promise<number | false> |
屏幕亮度;成功返回 0~1 数值,失败 resolve(false) |
getDomInfo |
(params: GetDomInfoParams): Promise<SelectorQueryNodeInfo[]> |
节点布局信息;selector/component 为空时 reject(new Error(...)),需 try/catch |
getImageInfo |
(params?: GetImageInfoParams): Promise<GetImageInfoResult | false> |
图片信息;src 经 urlConversion;src 空或失败 resolve(false) |
getSystemInfoSync |
(): GetSystemInfoSyncResult |
同步;合并官方 5 个 getter(替代废弃 getSystemInfoSync) |
rpxToPx |
(rpx: number): number |
rpx → px;公式 rpx * screenWidth / 750;screenWidth 经 getSystemInfoSync() 读取并 Number() 兜底 750;非 uni 环境由 getUni() 抛错 |
pxToRpx |
(px: number): number |
px → rpx;公式 px * 750 / screenWidth;screenWidth 同样 Number() 兜底 750;非 uni 环境由 getUni() 抛错 |
backRefresh |
(options?: Partial<BackRefreshOptions>): void |
返回上一页并调用其 $vm 方法(默认 refreshPage,携带 data);设置 path 时经 switchTab/redirectTo 跳转目标页(data 经 queryString 序列化);无上一页兜底首页;delta≥1、duration≥0,延迟执行规避页面栈未就绪 |
storageWatcher |
class StorageWatcher + export const storageWatcher: StorageWatcher(全局唯一单例) |
可监听本地缓存事件中心(class 封装);基于 uni 缓存 API,支持指定 key 与全局 "*" 监听、变更早于监听注册时的暂存事件自动补发;setStorageWatch/setStorageWatchAsync/removeStorageWatch/clearStorageWatch 触发变更;watchStorage 返回取消函数 |
import {
showToast,
chooseMedia,
scanCode,
getLoginCode,
getSystemInfoSync,
rpxToPx,
pxToRpx,
backRefresh,
storageWatcher, // 可监听本地缓存事件中心(全局唯一单例,推荐直接使用)
} from "@xiaojinquan/super-kit/utils";
showToast("保存成功");
const media = await chooseMedia({ count: 1, mediaType: ["image"] });
if (media) console.log(media.tempFiles);
const scanned = await scanCode(); // 默认 scanType: ['qrCode','barCode']
if (scanned) console.log(scanned.result, scanned.scanType);
const code = await getLoginCode();
if (code) console.log(code);
const sys = getSystemInfoSync(); // 同步返回
const px = rpxToPx(100); // 设备屏宽 375 时返回 50
const rpx = pxToRpx(50); // 返回 100
失败处理约定:多数 choose / 文件类方法(chooseMessageFile chooseMedia scanCode chooseLocation getLocation downloadFile openDocument getScreenBrightness getImageInfo getLoginCode addPhoneContact)失败 resolve(false)、不 reject,调用方 if (res) 判空即可;getDomInfo 对入参错误 reject,需 try/catch;getSystemInfoSync 为同步函数。部分能力为微信小程序 / App 专属(如 saveImageToPhotosAlbum 相册权限、addPhoneContact 通讯录权限、5 个 getter),H5 / 各端支持度不同,宜按平台条件调用(如 #ifdef MP-WEIXIN)。
4.16.1 storageWatcher — 可监听本地缓存事件中心(全局唯一单例)
对 uni 本地缓存(getStorageSync / setStorageSync / setStorage / removeStorageSync / getStorageInfoSync / clearStorageSync)做可监听封装。**已封装为 class StorageWatcher,并导出全局唯