npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ly-utils-lib

v2.11.1

Published

一个功能强大的 JavaScript/TypeScript 工具函数库,提供日期、数组、字符串、对象、Excel、PDF、地图、存储、加密解密、颜色转换、图片处理等常用功能的封装

Downloads

914

Readme

Utils Toolkit

npm version npm downloads License TypeScript CI PRs Welcome Code style: prettier

一个功能强大的 JavaScript/TypeScript 工具函数库,提供日期、数组、字符串、对象、Excel、PDF、存储等常用功能的封装。

特性:

  • ✅ 完全的 TypeScript 支持
  • ✅ 模块化设计,按需导入
  • ✅ 零依赖或轻量级依赖
  • ✅ 丰富的 API 文档
  • ✅ 完善的类型定义
  • ✅ 100% 测试覆盖

核心依赖:

安装

npm install ly-utils-lib
# 或
yarn add ly-utils-lib
# 或
pnpm add ly-utils-lib

快速开始

完整导入

import * as utils from 'ly-utils-lib'

// 使用日期功能
const now = utils.date.now()
const formatted = utils.date.format(now, 'YYYY-MM-DD HH:mm:ss')

// 使用数组功能
const arr = [1, 2, 2, 3]
const unique = utils.array.unique(arr)

// 使用字符串功能
const camel = utils.string.camelCase('hello-world')

按需导入(推荐)

// 只导入日期模块
import { format, add, diffDays } from 'ly-utils-lib/date'

// 只导入数组模块
import { unique, chunk, groupBy } from 'ly-utils-lib/array'

// 只导入字符串模块
import { camelCase, uuid, random } from 'ly-utils-lib/string'

// 只导入对象模块
import { pick, omit, merge } from 'ly-utils-lib/object'

// 只导入 Excel 模块
import { exportExcel, importExcel } from 'ly-utils-lib/excel'

// 只导入 PDF 模块
import { captureToPDF, createPDF } from 'ly-utils-lib/pdf'

// 只导入 WebSocket 模块
import { createWebSocket, quickConnect } from 'ly-utils-lib/websocket'

// 只导入 Event 模块
import { createEventBus, waitForEvent } from 'ly-utils-lib/event'

模块文档

📅 Date Module - 日期处理

基于 dayjs 封装,提供丰富的日期处理功能。

import {
  now,
  format,
  add,
  subtract,
  diffDays,
  isToday,
  isBetween,
  getMonthRange,
  getWeekRange,
} from 'ly-utils-lib/date'

// 获取当前时间
const current = now()

// 格式化日期
const formatted = format(new Date(), 'YYYY-MM-DD HH:mm:ss')

// 日期计算
const nextWeek = add(new Date(), 7, 'day')
const lastMonth = subtract(new Date(), 1, 'month')

// 日期比较
const diff = diffDays(new Date(), '2024-01-01')
const today = isToday(new Date())

// 获取日期范围
const [monthStart, monthEnd] = getMonthRange()
const [weekStart, weekEnd] = getWeekRange()

API 列表:

| 函数 | 说明 | 示例 | | ------------------------------ | ---------------- | ---------------------------------- | | now() | 获取当前时间 | now() | | format(date, formatStr) | 格式化日期 | format(new Date(), 'YYYY-MM-DD') | | getDate(date) | 获取日期 | getDate() | | getTime(date) | 获取时间 | getTime() | | add(date, amount, unit) | 日期加 | add(new Date(), 7, 'day') | | subtract(date, amount, unit) | 日期减 | subtract(new Date(), 1, 'month') | | diffDays(date1, date2) | 日期天数差 | diffDays(date1, date2) | | isToday(date) | 判断是否今天 | isToday(new Date()) | | isBetween(date, start, end) | 判断是否在范围内 | isBetween(date, start, end) | | getMonthRange(date) | 获取月份范围 | getMonthRange() | | getWeekRange(date, startDay) | 获取周范围 | getWeekRange() | | getQuarterRange(date) | 获取季度范围 | getQuarterRange() | | getYearRange(date) | 获取年份范围 | getYearRange() |

📊 Array Module - 数组处理

基于 es-toolkit 封装,提供高效的数组处理功能。

import {
  unique,
  shuffle,
  chunk,
  groupBy,
  arrayToTree,
  treeToArray,
  paginate,
  reduceSum,
  average,
  maxValue,
  minValue,
  forEachAsync,
  forEachRight,
  forEach,
} from 'ly-utils-lib/array'

// 数组去重
const arr = [1, 2, 2, 3, 4, 4]
const uniqueArr = unique(arr) // [1, 2, 3, 4]

// 数组乱序
const shuffled = shuffle([1, 2, 3, 4, 5])

// 数组分块
const chunks = chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]

// 数组分组
const grouped = groupBy(
  [
    { id: 1, type: 'A' },
    { id: 2, type: 'B' },
    { id: 3, type: 'A' },
  ],
  item => item.type
)

// 数组转树
const tree = arrayToTree([
  { id: 1, parentId: null },
  { id: 2, parentId: 1 },
  { id: 3, parentId: 1 },
])

// 树转数组
const flat = treeToArray(tree)

// 分页
const pageData = paginate([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2, 3) // [4, 5, 6]

// 统计
const nums = [1, 2, 3, 4, 5]
const sum = reduceSum(nums) // 15
const avg = average(nums) // 3
const max = maxValue(nums) // 5
const min = minValue(nums) // 1

// 遍历数组(返回原数组)
const result = forEach([1, 2, 3], (value) => {
  console.log(value) // 输出 1, 2, 3
})
console.log(result) // [1, 2, 3] (返回原数组)

// 遍历对象
const obj = { a: 1, b: 2, c: 3 }
forEach(obj, (value, key) => {
  console.log(key, value) // 输出 a 1, b 2, c 3
})

// 遍历字符串
forEach('hello', (char) => {
  console.log(char) // 输出 h, e, l, l, o
})

// 异步遍历
const users = [{ id: 1 }, { id: 2 }, { id: 3 }]
await forEachAsync(users, async (user) => {
  await updateUser(user.id)
})

// 异步遍历(带并发限制)
await forEachAsync(
  items,
  async (item) => await processItem(item),
  { concurrency: 2 }
)

// 从右到左遍历
const arrReverse: number[] = []
forEachRight([1, 2, 3], (value) => {
  arrReverse.push(value)
})
console.log(arrReverse) // [3, 2, 1]

API 列表:

| 函数 | 说明 | 示例 | | -------------------------------- | ---------------------- | --------------------------------- | | unique(arr, key?) | 数组去重 | unique([1, 2, 2, 3]) | | shuffle(arr) | 数组乱序 | shuffle([1, 2, 3]) | | chunk(arr, size) | 数组分块 | chunk([1, 2, 3, 4], 2) | | groupBy(arr, fn) | 数组分组 | groupBy(arr, x => x.type) | | arrayToTree(arr, options) | 数组转树 | arrayToTree(data) | | treeToArray(tree, childrenKey) | 树转数组 | treeToArray(tree) | | paginate(arr, page, pageSize) | 分页 | paginate(arr, 1, 10) | | reduceSum(arr, mapper) | 求和 | reduceSum([1, 2, 3]) | | average(arr, mapper) | 平均值 | average([1, 2, 3]) | | maxValue(arr, mapper) | 最大值 | maxValue([1, 2, 3]) | | minValue(arr, mapper) | 最小值 | minValue([1, 2, 3]) | | move(arr, from, to) | 移动元素 | move([1, 2, 3], 0, 2) | | split(arr, size) | 分割数组 | split([1, 2, 3, 4], 2) | | forEach(collection, fn) | 遍历(兼容 lodash) | forEach([1, 2], fn) | | forEachAsync(arr, fn, options?) | 异步遍历数组(支持并发控制) | await forEachAsync(arr, async fn, { concurrency: 2 }) | | forEachRight(arr, fn) | 从右到左遍历数组 | forEachRight([1, 2, 3], fn) | | map(collection, fn) | 映射(兼容 lodash) | map([1, 2], x => x * 2) | | filter(collection, fn) | 过滤(兼容 lodash) | filter([1, 2], x => x > 1) | | includes(collection, value) | 判断包含(兼容 lodash)| includes([1, 2], 1) | | find(collection, fn) | 查找(兼容 lodash) | find([1, 2], x => x > 1) | | findIndex(collection, fn) | 查找索引(兼容 lodash)| findIndex([1, 2], x => x > 1) | | some(collection, fn) | 判断是否存在(兼容 lodash)| some([1, 2], x => x > 1) | | indexOf(collection, value) | 查找位置(兼容 lodash)| indexOf([1, 2], 1) |

📝 String Module - 字符串处理

基于 es-toolkit 封装,提供丰富的字符串处理功能。

import {
  camelCase,
  kebabCase,
  snakeCase,
  uuid,
  shortId,
  random,
  formatMoney,
  hidePhone,
  hideEmail,
  isPhone,
  isEmail,
  isUrl,
  highlight,
} from 'ly-utils-lib/string'

// 字符串转换
const camel = camelCase('hello-world') // 'helloWorld'
const kebab = kebabCase('helloWorld') // 'hello-world'
const snake = snakeCase('helloWorld') // 'hello_world'

// 生成 ID
const id = uuid() // 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
const short = shortId(6) // 'aB3dE6'

// 生成随机字符串
const randomStr = random(8) // 'aB3dE6fG'

// 格式化金额
const money = formatMoney(1234567.89) // '1,234,567.89'

// 隐藏敏感信息
const phone = hidePhone('13812345678') // '138****5678'
const email = hideEmail('[email protected]') // 'a***[email protected]'

// 验证
const validPhone = isPhone('13812345678') // true
const validEmail = isEmail('[email protected]') // true
const validUrl = isUrl('https://example.com') // true

// 高亮关键词
const highlighted = highlight('Hello World', 'World') // 'Hello <span class="highlight">World</span>'

API 列表:

| 函数 | 说明 | 示例 | | ------------------------------------ | -------------- | -------------------------------- | | camelCase(str) | 驼峰命名 | camelCase('hello-world') | | kebabCase(str) | 短横命名 | kebabCase('helloWorld') | | snakeCase(str) | 蛇形命名 | snakeCase('helloWorld') | | replace(str, pattern, replacement) | 替换字符串 | replace('hello', 'l', 'L') | | uuid() | 生成 UUID | uuid() | | shortId(length) | 生成短 ID | shortId(6) | | random(length, charset) | 随机字符串 | random(8) | | formatMoney(amount, decimals, sep) | 格式化金额 | formatMoney(1234.56) | | hidePhone(phone) | 隐藏手机号 | hidePhone('138****5678') | | hideEmail(email) | 隐藏邮箱 | hideEmail('a***[email protected]') | | isPhone(phone) | 验证手机号 | isPhone('13812345678') | | isEmail(email) | 验证邮箱 | isEmail('[email protected]') | | isUrl(url) | 验证 URL | isUrl('https://example.com') | | highlight(text, keyword) | 高亮关键词 | highlight(text, 'keyword') | | getExtension(filename) | 获取文件扩展名 | getExtension('file.txt') | | toNumber(str, default) | 转数字 | toNumber('123', 0) | | toBoolean(str, default) | 转布尔值 | toBoolean('true', false) |

📦 Object Module - 对象处理

基于 es-toolkit 封装,提供强大的对象处理功能。

import {
  pick,
  omit,
  merge,
  cloneDeep,
  deepMerge,
  isEmpty,
  isObject,
  isArray,
  toQueryString,
  fromQueryString,
  toFormData,
  diff,
  getDeep,
  setDeep,
} from 'ly-utils-lib/object'

// 对象操作
const obj = { name: 'Alice', age: 25, city: 'Beijing' }
const picked = pick(obj, ['name', 'age']) // { name: 'Alice', age: 25 }
const omitted = omit(obj, ['city']) // { name: 'Alice', age: 25 }

// 合并对象
const merged = merge({ a: 1 }, { b: 2 }) // { a: 1, b: 2 }
const deepMerged = deepMerge({ a: { b: 1 } }, { a: { c: 2 } }) // { a: { b: 1, c: 2 } }

// 克隆
const cloned = cloneDeep(obj)

// 判断类型
const empty = isEmpty({}) // true
const isObj = isObject({}) // true
const isArr = isArray([]) // true

// 查询字符串转换
const params = { name: 'Alice', age: '25' }
const qs = toQueryString(params) // 'name=Alice&age=25'
const parsed = fromQueryString(qs) // { name: 'Alice', age: '25' }

// FormData 转换
const formData = toFormData({ name: 'Alice', age: 25 })

// 对象差值
const base = { a: 1, b: 2 }
const changed = { a: 1, b: 3 }
const diffed = diff(changed, base) // { b: 3 }

// 嵌套路径操作
const nested = { user: { name: 'Alice', age: 25 } }
const name = getDeep(nested, 'user.name') // 'Alice'
setDeep(nested, 'user.age', 26)

API 列表:

| 函数 | 说明 | 示例 | | ------------------------------- | ---------------- | --------------------------------- | | pick(obj, keys) | 选择属性 | pick(obj, ['a', 'b']) | | omit(obj, keys) | 排除属性 | omit(obj, ['a']) | | merge(target, ...sources) | 浅合并 | merge({a:1}, {b:2}) | | deepMerge(target, ...sources) | 深度合并 | deepMerge({a:{b:1}}, {a:{c:2}}) | | cloneDeep(obj) | 深度克隆 | cloneDeep(obj) | | isEmpty(obj) | 判断为空 | isEmpty({}) | | isObject(obj) | 判断对象 | isObject({}) | | isArray(obj) | 判断数组 | isArray([]) | | toQueryString(obj) | 对象转查询字符串 | toQueryString({a:1}) | | fromQueryString(str) | 查询字符串转对象 | fromQueryString('a=1') | | toFormData(obj) | 对象转 FormData | toFormData({a:1}) | | getDeep(obj, path, default) | 获取嵌套值 | getDeep(obj, 'a.b.c') | | setDeep(obj, path, value) | 设置嵌套值 | setDeep(obj, 'a.b', 1) | | diff(obj, base) | 对象差值 | diff({a:2}, {a:1}) | | mapValues(obj, mapper) | 映射值 | mapValues(obj, v => v * 2) | | filter(obj, predicate) | 过滤键值对 | filter(obj, v => v > 0) |

📈 Excel Module - Excel 处理

基于 xlsx 封装,提供 Excel 导入导出功能。

import {
  exportExcel,
  exportMultiSheetExcel,
  importExcel,
  importAllSheetsExcel,
  exportExcelWithHeaders,
  getSheetNames,
} from 'ly-utils-lib/excel'

// 导出 Excel
const data = [
  { name: 'Alice', age: 25, city: 'Beijing' },
  { name: 'Bob', age: 30, city: 'Shanghai' },
]

exportExcel(data, {
  filename: 'export.xlsx',
  sheetName: 'Users',
  header: { name: '姓名', age: '年龄', city: '城市' },
})

// 导出多 Sheet Excel
exportMultiSheetExcel(
  [
    {
      name: 'Users',
      data: [{ name: 'Alice', age: 25 }],
      header: { name: '姓名', age: '年龄' },
    },
    {
      name: 'Products',
      data: [{ product: 'Apple', price: 10 }],
      header: { product: '产品', price: '价格' },
    },
  ],
  'multi-sheet.xlsx'
)

// 导入 Excel
const fileInput = document.querySelector('input[type="file"]')
const file = fileInput.files[0]
const importedData = await importExcel(file)

// 导入所有 Sheet
const allSheetsData = await importAllSheetsExcel(file)

// 获取 Sheet 列表
const sheetNames = await getSheetNames(file)

// 自定义表头导出
exportExcelWithHeaders(
  [{ name: 'Alice', age: 25 }],
  [
    { key: 'name', label: '姓名' },
    { key: 'age', label: '年龄' },
  ],
  'custom.xlsx'
)

API 列表:

| 函数 | 说明 | 示例 | | ---------------------------------------------------- | --------------- | ------------------------------------------------------------- | | exportExcel(data, options) | 导出 Excel | exportExcel(data, {filename: 'test.xlsx'}) | | exportMultiSheetExcel(sheetsData, filename) | 导出多 Sheet | exportMultiSheetExcel([{name: 'Sheet1', data: []}]) | | importExcel(file, options) | 导入 Excel | importExcel(file) | | importAllSheetsExcel(file, options) | 导入所有 Sheet | importAllSheetsExcel(file) | | exportExcelWithHeaders(data, headers, filename) | 自定义表头导出 | exportExcelWithHeaders(data, headers) | | getSheetNames(file) | 获取 Sheet 列表 | getSheetNames(file) | | exportExcelWithColumnWidths(data, widths, options) | 设置列宽导出 | exportExcelWithColumnWidths(data, [{wch: 20}]) | | exportExcelWithMerges(data, merges, options) | 合并单元格导出 | exportExcelWithMerges(data, [{s: {r:0,c:0}, e: {r:1,c:1}}]) |

📄 PDF Module - PDF 处理

基于 html2canvasjspdf 封装,提供 PDF 生成功能。

import {
  captureToPDF,
  captureToPDFWithPagination,
  captureToImage,
  captureToImageDownload,
  createPDF,
  addTextToPDF,
  addImageToPDF,
  savePDF,
} from 'ly-utils-lib/pdf'

// 将 DOM 元素转换为 PDF
const element = document.querySelector('.content')
await captureToPDF(element, {
  filename: 'document.pdf',
  scale: 2,
  margin: 10,
})

// 分页导出
await captureToPDFWithPagination(element, {
  filename: 'document-paged.pdf',
})

// 截取为图片
const imageData = await captureToImage(element)
await captureToImageDownload(element, 'screenshot.png')

// 手动创建 PDF
const pdf = createPDF({ orientation: 'portrait', format: 'a4' })

// 添加文本
addTextToPDF(pdf, 'Hello World', 10, 10, {
  fontSize: 16,
  align: 'center',
})

// 添加图片
addImageToPDF(pdf, imageData, 10, 30, 100, 100)

// 保存 PDF
savePDF(pdf, 'custom.pdf')

API 列表:

| 函数 | 说明 | 示例 | | ---------------------------------------------------- | -------------- | ----------------------------------------------- | | captureToPDF(element, options) | DOM 转 PDF | captureToPDF(element, {filename: 'test.pdf'}) | | captureToPDFWithPagination(element, options) | 分页导出 | captureToPDFWithPagination(element) | | captureToImage(element, options) | DOM 转图片 | captureToImage(element) | | captureToImageDownload(element, filename, options) | DOM 转图片下载 | captureToImageDownload(element, 'pic.png') | | createPDF(options) | 创建空白 PDF | createPDF({format: 'a4'}) | | addTextToPDF(pdf, text, x, y, options) | 添加文本 | addTextToPDF(pdf, 'text', 10, 10) | | addImageToPDF(pdf, imageData, x, y, w, h) | 添加图片 | addImageToPDF(pdf, data, 10, 10, 100, 100) | | addTableToPDF(pdf, headers, data, options) | 添加表格 | addTableToPDF(pdf, ['A'], [['1']]) | | addPage(pdf) | 添加新页面 | addPage(pdf) | | savePDF(pdf, filename) | 保存 PDF | savePDF(pdf, 'doc.pdf') | | pdfToDataURL(pdf) | PDF 转 DataURL | pdfToDataURL(pdf) | | pdfToBlob(pdf) | PDF 转 Blob | pdfToBlob(pdf) |

🗺️ Map Module - 地图处理

基于 OpenLayers 封装,提供强大的地图操作功能。

import {
  MapInstance,
  createOSMLayer,
  createGaodeLayer,
  createTiandituLayer,
  lonLatToXY,
  xyToLonLat,
} from 'ly-utils-lib/map'

// 创建地图
const map = new MapInstance({
  container: 'map-container',
  center: [116.3974, 39.9093], // 北京
  zoom: 10,
  showScaleLine: true,
  showFullScreen: true,
})

// 添加 OSM 图层
const osmLayer = createOSMLayer()
map.addLayer(osmLayer)

// 添加高德地图图层
const gaodeLayer = createGaodeLayer()
map.addLayer(gaodeLayer)

// 添加天地图图层(需要 token)
const tiandituLayer = createTiandituLayer('your-token', 'vec')
map.addLayer(tiandituLayer)

// 添加标记
const marker = map.addMarker({
  coordinate: [116.3974, 39.9093],
  color: '#ff3333',
  radius: 8,
})

// 移除标记
map.removeMarker(marker)

// 设置中心点和缩放
map.setCenter([121.4737, 31.2304]) // 上海
map.setZoom(12)

// 获取中心点
const center = map.getCenter() // [121.4737, 31.2304]

// 获取缩放级别
const zoom = map.getZoom() // 12

// 缩放到指定范围
map.fit([1000000, 6000000, 2000000, 7000000])

// 绘制点
map.startDraw({
  type: 'Point',
  onDrawEnd: feature => {
    console.log('绘制完成', feature)
  },
})

// 绘制线
map.startDraw({
  type: 'LineString',
  onDrawEnd: feature => {
    console.log('绘制完成', feature)
  },
})

// 绘制面
map.startDraw({
  type: 'Polygon',
  onDrawEnd: feature => {
    console.log('绘制完成', feature)
  },
})

// 停止绘制
map.stopDraw()

// 开始编辑
map.startModify()

// 停止编辑
map.stopModify()

// 选择要素
map.startSelect(features => {
  console.log('选中的要素:', features)
})

// 停止选择
map.stopSelect()

// 获取所有要素
const features = map.getFeatures()

// 清除所有矢量要素
map.clearFeatures()

// 事件监听
map.on('click', evt => {
  console.log('点击位置:', evt.coordinate)
})

map.on('moveend', () => {
  console.log('地图移动结束', map.getCenter())
})

// 更新地图大小(容器大小改变时)
map.updateSize()

// 销毁地图
map.destroy()

API 列表:

| 类/函数 | 说明 | 示例 | | ---------------------------------------- | -------------- | ----------------------------------------- | | new MapInstance(options) | 创建地图实例 | new MapInstance({container: 'map'}) | | map.setCenter(coord) | 设置中心点 | map.setCenter([116.39, 39.90]) | | map.getCenter() | 获取中心点 | map.getCenter() | | map.setZoom(zoom) | 设置缩放级别 | map.setZoom(10) | | map.getZoom() | 获取缩放级别 | map.getZoom() | | map.fit(extent) | 缩放到范围 | map.fit([minX, minY, maxX, maxY]) | | map.addLayer(layer) | 添加图层 | map.addLayer(createOSMLayer()) | | map.removeLayer(layer) | 移除图层 | map.removeLayer(layer) | | map.addMarker(options) | 添加标记 | map.addMarker({coordinate: [lon, lat]}) | | map.removeMarker(feature) | 移除标记 | map.removeMarker(marker) | | map.clearFeatures() | 清除所有要素 | map.clearFeatures() | | map.startDraw(options) | 开始绘制 | map.startDraw({type: 'Point'}) | | map.stopDraw() | 停止绘制 | map.stopDraw() | | map.startModify() | 开始编辑 | map.startModify() | | map.stopModify() | 停止编辑 | map.stopModify() | | map.startSelect(callback) | 开始选择 | map.startSelect((f) => console.log(f)) | | map.stopSelect() | 停止选择 | map.stopSelect() | | map.getFeatures() | 获取所有要素 | map.getFeatures() | | map.getSelectedFeatures() | 获取选中要素 | map.getSelectedFeatures() | | map.on(event, callback) | 事件监听 | map.on('click', (e) => {}) | | map.off(event, callback) | 移除监听 | map.off('click', callback) | | map.updateSize() | 更新地图大小 | map.updateSize() | | map.destroy() | 销毁地图 | map.destroy() | | createOSMLayer(name) | 创建 OSM 图层 | createOSMLayer('OSM') | | createXYZLayer(url, name) | 创建 XYZ 图层 | createXYZLayer(url, 'Custom') | | createGaodeLayer(name) | 创建高德图层 | createGaodeLayer('高德') | | createTiandituLayer(token, type, name) | 创建天地图图层 | createTiandituLayer('token', 'vec') | | createVectorLayer(name) | 创建矢量图层 | createVectorLayer('Vector') | | lonLatToXY(lon, lat) | 经纬度转投影 | lonLatToXY(116.39, 39.90) | | xyToLonLat(x, y) | 投影转经纬度 | xyToLonLat(x, y) |

🎯 Event Module - 事件管理

基于 mitt 封装的轻量级事件发布订阅系统,提供类型安全的事件管理。

import {
  createEventBus,
  getGlobalEventBus,
  waitForEvent,
  batchSubscribe,
  createNamespacedEventBus,
} from 'ly-utils-lib/event'

// 定义事件类型
interface AppEvents {
  'user:login': { id: number; name: string }
  'user:logout': never
  'data:loaded': { data: any[] }
  'error': Error
}

// 方式 1: 创建类型化的事件总线
const bus = createEventBus<AppEvents>({ debug: true })

// 订阅事件
const unsubscribe = bus.on('user:login', (user) => {
  console.log('User logged in:', user.name)
})

// 订阅一次性事件
bus.once('data:loaded', (data) => {
  console.log('Data loaded:', data.data)
})

// 发布事件
bus.emit('user:login', { id: 1, name: 'Alice' })
bus.emit('user:logout')
bus.emit('error', new Error('Something went wrong'))

// 取消订阅
unsubscribe()

// 方式 2: 批量订阅
batchSubscribe(bus, {
  'user:login': (user) => console.log('Login:', user),
  'user:logout': () => console.log('Logout'),
  'error': (error) => console.error('Error:', error),
})

// 方式 3: 等待事件触发
const userData = await waitForEvent<{ id: number; name: string }>(
  bus,
  'user:login',
  5000
)
console.log('User logged in:', userData.name)

// 方式 4: 使用命名空间
const userBus = createNamespacedEventBus('user')
const appBus = createNamespacedEventBus('app')

userBus.emit('login') // 实际事件名: user:login
appBus.emit('ready')  // 实际事件名: app:ready

// 方式 5: 使用全局事件总线
const globalBus = getGlobalEventBus({ debug: true })
globalBus.emit('app:ready')

API 列表:

创建事件总线

| 类/函数 | 说明 | 示例 | | --------------------------------------------- | --------------------- | -------------------------------------- | | createEventBus<E>(options) | 创建事件总线 | createEventBus({debug: true}) | | getGlobalEventBus<E>(options?) | 获取全局事件总线 | getGlobalEventBus() | | createNamespacedEventBus<E>(namespace) | 创建命名空间总线 | createNamespacedEventBus('user') |

订阅事件

| 类/函数 | 说明 | 示例 | | --------------------------------------------- | --------------------- | -------------------------------------- | | bus.on(event, handler) | 订阅事件 | bus.on('click', handler) | | bus.once(event, handler) | 订阅一次事件 | bus.once('init', handler) | | batchSubscribe(bus, events) | 批量订阅 | batchSubscribe(bus, {...}) | | waitForEvent(bus, event, timeout) | 等待事件触发 | waitForEvent(bus, 'ready', 5000) |

发布事件

| 类/函数 | 说明 | 示例 | | --------------------------------------------- | --------------------- | -------------------------------------- | | bus.emit(event, data?) | 发布事件 | bus.emit('click', {x, y}) |

取消订阅

| 类/函数 | 说明 | 示例 | | --------------------------------------------- | --------------------- | -------------------------------------- | | bus.off(event, handler?) | 取消订阅 | bus.off('click', handler) | | bus.clear() | 清空所有监听器 | bus.clear() |

查询方法

| 类/函数 | 说明 | 示例 | | --------------------------------------------- | --------------------- | -------------------------------------- | | bus.getListenerCount(event?) | 获取监听器数量 | bus.getListenerCount() | | bus.getEventNames() | 获取所有事件名 | bus.getEventNames() | | bus.getListeners(event) | 获取监听器列表 | bus.getListeners('click') |

配置选项

| 选项 | 说明 | 默认值 | | --------------------------------------------- | --------------------- | -------------------------------------- | | debug | 调试日志 | true | | prefix | 事件名前缀 | '' |

高级功能

  • ✅ 类型安全的事件定义
  • ✅ 支持命名空间
  • ✅ 支持全局单例
  • ✅ 批量订阅/取消
  • ✅ 等待事件触发(Promise)
  • ✅ 一次性事件
  • ✅ 监听器管理
  • ✅ 调试日志

🔌 WebSocket Module - WebSocket 工具

提供简化的 WebSocket 连接、消息发送、心跳检测和重连机制。

import {
  createWebSocket,
  quickConnect,
  WebSocketState,
} from 'ly-utils-lib/websocket'

// 方式 1: 使用 createWebSocket
const ws = createWebSocket({
  url: 'echo.websocket.org',
  autoReconnect: true,
  reconnectAttempts: 3,
  heartbeatInterval: 30000,
  onOpen: (event) => console.log('Connected'),
  onMessage: (data, event) => console.log('Received:', data),
  onClose: (event) => console.log('Disconnected'),
  onError: (event) => console.error('Error:', event),
  onReconnect: (attempt) => console.log(`Reconnecting... (${attempt})`),
  onHeartbeat: () => console.log('Heartbeat'),
})

// 发送消息
ws.send('Hello, WebSocket!')
ws.send({ type: 'message', content: 'Hello' })

// 检查连接状态
if (ws.isConnected()) {
  console.log('Connected')
}

// 断开连接
ws.disconnect()

// 方式 2: 使用 quickConnect
const ws2 = quickConnect('echo.websocket.org', {
  onMessage: (data) => console.log('Received:', data),
})

// 重新连接
ws.reconnect()

API 列表:

创建客户端

| 类/函数 | 说明 | 示例 | | --------------------------------------------- | --------------------- | -------------------------------------- | | createWebSocket(options) | 创建 WebSocket 客户端 | createWebSocket({url: '...'}) | | quickConnect(url, handlers?) | 快速连接 | quickConnect('...') | | WebSocketClient | WebSocket 客户端类 | new WebSocketClient({url: '...'}) |

连接管理

| 类/函数 | 说明 | 示例 | | --------------------------------------------- | --------------------- | -------------------------------------- | | connect() | 连接 | ws.connect() | | disconnect() | 断开连接 | ws.disconnect() | | reconnect() | 重新连接 | ws.reconnect() | | getState() | 获取连接状态 | ws.getState() | | isConnected() | 是否已连接 | ws.isConnected() | | getInstance() | 获取 WebSocket 实例 | ws.getInstance() |

消息发送

| 类/函数 | 说明 | 示例 | | --------------------------------------------- | --------------------- | -------------------------------------- | | send(data) | 发送消息(异步) | ws.send('Hello') | | sendSync(data) | 发送消息(同步) | ws.sendSync('Hello') |

事件处理

| 类/函数 | 说明 | 示例 | | --------------------------------------------- | --------------------- | -------------------------------------- | | on(event, handler) | 设置事件处理器 | ws.on('message', handler) | | off(event, handler?) | 移除事件处理器 | ws.off('message', handler) |

配置选项

| 选项 | 说明 | 默认值 | | --------------------------------------------- | --------------------- | -------------------------------------- | | url | WebSocket 地址 | - | | protocol | 协议 (ws/wss) | 自动检测 | | protocols | 子协议 | [] | | autoReconnect | 自动重连 | true | | reconnectAttempts | 重连次数 | 3 | | reconnectInterval | 重连间隔(ms) | 3000 | | heartbeatInterval | 心跳间隔(ms) | 30000 | | heartbeatMessage | 心跳消息 | 'ping' | | heartbeatTimeout | 心跳超时(ms) | 5000 | | connectTimeout | 连接超时(ms) | 10000 | | debug | 调试日志 | true |

事件处理器

| 事件 | 说明 | 示例 | | --------------------------------------------- | --------------------- | -------------------------------------- | | onOpen | 连接成功 | onOpen: (event) => void | | onMessage | 接收消息 | onMessage: (data, event) => void | | onClose | 连接关闭 | onClose: (event) => void | | onError | 错误 | onError: (event) => void | | onReconnect | 重连开始 | onReconnect: (attempt) => void | | onReconnectSuccess | 重连成功 | onReconnectSuccess: (attempt) => void| | onReconnectFailed | 重连失败 | onReconnectFailed: () => void | | onHeartbeat | 心跳 | onHeartbeat: () => void | | onHeartbeatTimeout | 心跳超时 | onHeartbeatTimeout: () => void |

💾 Storage Module - 存储处理

基于浏览器 Web Storage API 和 Cookie(使用 js-cookie 封装),提供统一的存储操作功能。

import {
  setLocal,
  getLocal,
  removeLocal,
  clearLocal,
  setSession,
  getSession,
  setCookie,
  getCookie,
  removeCookie,
  getAllCookies,
  hasCookie,
  setCookieJSON,
  getCookieJSON,
  getCookieSize,
  setStorage,
  getStorage,
  removeStorage,
} from 'ly-utils-lib/storage'

// LocalStorage 操作
setLocal('user', { name: 'Alice', age: 25 })
const user = getLocal<{ name: string; age: number }>('user')
console.log(user?.name) // 'Alice'

// 带过期时间的存储
setLocal('token', 'abc123', { ttl: 3600000 }) // 1小时后过期
const token = getLocal('token')

// SessionStorage 操作
setSession('temp', { data: [1, 2, 3] })
const temp = getSession('temp')

// Cookie 操作(支持对象类型)
setCookie('token', 'abc123', { days: 7, secure: true })
setCookie('user', { name: 'Alice', age: 25 }, { days: 30 }) // 自动序列化对象
const cookieToken = getCookie('token')

// JSON 格式 Cookie
setCookieJSON('config', { theme: 'dark', lang: 'zh-CN' }, { days: 7 })
const config = getCookieJSON<{ theme: string; lang: string }>('config')

// Cookie 工具函数
if (hasCookie('token')) {
  console.log('Token exists')
}
const cookieSize = getCookieSize() // 获取 Cookie 数量
const allCookies = getAllCookies() // 获取所有 Cookie

// 统一接口
setStorage('local', 'user', { name: 'Alice' })
setStorage('cookie', 'token', 'abc123', { days: 7 })
const user = getStorage<{ name: string }>('local', 'user')
const token = getStorage('cookie', 'token')

// 清除操作
removeLocal('user')
removeCookie('token')
clearStorage('local')

API 列表:

LocalStorage

| 类/函数 | 说明 | 示例 | | --------------------------------- | --------------- | -------------------------------------- | | setLocal(key, value, options) | 设置永久缓存 | setLocal('user', {name: 'Alice'}) | | getLocal<T>(key) | 获取永久缓存 | getLocal<User>('user') | | removeLocal(key) | 移除永久缓存 | removeLocal('user') | | clearLocal() | 清除永久缓存 | clearLocal() | | getLocalKeys() | 获取所有键 | getLocalKeys() | | getLocalSize() | 获取键数量 | getLocalSize() |

SessionStorage

| 类/函数 | 说明 | 示例 | | --------------------------------- | --------------- | -------------------------------------- | | setSession(key, value, options) | 设置临时缓存 | setSession('temp', {data: [1,2,3]}) | | getSession<T>(key) | 获取临时缓存 | getSession<Data>('temp') | | removeSession(key) | 移除临时缓存 | removeSession('temp') | | clearSession() | 清除临时缓存 | clearSession() | | getSessionKeys() | 获取所有键 | getSessionKeys() | | getSessionSize() | 获取键数量 | getSessionSize() |

Cookie (基于 js-cookie)

| 类/函数 | 说明 | 示例 | | --------------------------------- | --------------- | -------------------------------------- | | setCookie(key, value, options) | 设置 Cookie | setCookie('token', 'abc', {days: 7}) | | getCookie(key) | 获取 Cookie | getCookie('token') | | removeCookie(key, options) | 移除 Cookie | removeCookie('token', {path: '/'}) | | getAllCookies() | 获取所有 Cookie | getAllCookies() | | hasCookie(key) | 检查 Cookie 是否存在 | hasCookie('token') | | getCookieJSON<T>(key) | 获取 JSON 格式 Cookie | getCookieJSON<User>('user') | | setCookieJSON(key, value, options) | 设置 JSON 格式 Cookie | setCookieJSON('config', {}, {days: 7}) | | getCookieSize() | 获取 Cookie 数量 | getCookieSize() |

统一接口

| 类/函数 | 说明 | 示例 | | --------------------------------- | --------------- | -------------------------------------- | | setStorage(type, key, value) | 统一设置存储 | setStorage('local', 'user', {}) | | getStorage<T>(type, key) | 统一获取存储 | getStorage('local', 'user') | | removeStorage(type, key) | 统一移除存储 | removeStorage('local', 'user') | | clearStorage(type) | 统一清除存储 | clearStorage('local') |

Demo

在线演示

查看完整功能的在线演示:

本地运行

# 克隆项目
git clone https://gitee.com/liyang517/ai-utils.git
cd ai-utils

# 安装依赖
pnpm install

# 构建项目
pnpm build

# 启动开发服务器
pnpm dev

然后在浏览器中打开:

  • 完整 Demo: http://localhost:5000/demo/
  • 地图 Demo: http://localhost:5000/demo/map.html

Demo 功能

完整 Demo 包含以下功能:

  • 📋 概览 - 项目介绍和快速开始
  • 📅 日期模块 - 日期格式化、计算、范围查询
  • 📊 数组模块 - 去重、统计、排序、转换
  • 📝 字符串模块 - 转换、ID 生成、验证、格式化
  • 📦 对象模块 - 操作、合并、查询、深度操作
  • 📈 Excel 模块 - 导入导出、多 Sheet 支持
  • 📄 PDF 模块 - DOM 转 PDF、自定义 PDF、截图
  • 🗺️ 地图模块 - 创建地图、图层切换、绘制、编辑、选择

地图 Demo 专门展示地图功能:

  • 多城市快速定位
  • OSM 和高德图层切换
  • 标记管理(添加、删除)
  • 绘制功能(点、线、面、圆形)
  • 编辑和选择功能
  • 实时状态显示

开发

# 安装依赖
pnpm install

# 构建
pnpm build

# 开发模式
pnpm dev

# 代码检查
pnpm lint
pnpm lint:fix

# 代码格式化
pnpm format

目录结构

utils-toolkit/
├── src/
│   ├── index.ts                 # 主入口
│   └── modules/
│       ├── date/                # 日期模块
│       ├── array/               # 数组模块
│       ├── string/              # 字符串模块
│       ├── object/              # 对象模块
│       ├── excel/               # Excel 模块
│       └── pdf/                 # PDF 模块
├── demo/                        # 示例
│   └── index.html
├── dist/                        # 构建输出
├── package.json
├── tsconfig.json
├── tsup.config.ts
└── README.md

贡献

欢迎贡献代码!请先阅读 贡献指南


许可证

MIT License

版本历史

v0.2.0 (最新)

  • 🗺️ 新增 Map 模块,基于 OpenLayers 10.8.0
  • ✨ 支持创建地图、添加图层、标记管理
  • ✨ 支持绘制功能(点、线、面、圆形)
  • ✨ 支持编辑和选择要素
  • ✨ 支持 OSM、高德、天地图等多种图层
  • ✨ 提供完整的类型定义和 API 文档
  • 📝 新增 Map 模块示例页面

v0.1.0

  • 🎉 初始版本发布
  • ✅ 实现六大核心模块
  • ✅ 支持 ESM 和 CJS 双格式

链接

📚 文档

致谢


Made with ❤️ by Your Team