@canvas-components/utils
v0.2.10
Published
Clipboard and export utilities for canvas-components.
Readme
@canvas-components/utils
@canvas-components/utils 提供表格包之间可复用的纯原生工具能力,覆盖日期时间、数据读取、剪贴板写入和导出文件。
功能作用
- 写入文本、二维表格文本、JSON 到系统剪贴板
- 通过
dataIndex安全读取嵌套数据 - 使用 Day.js 风格的常用 token 格式化日期时间,不依赖 Day.js 运行时
- 复用数字、金额、百分比、科学计数法和自定义数字格式化
- 复用数据路径比较、数值约束和矩形命中等纯函数
- 把行列数据导出为
csv、txt、xlsx - 生成导出前的中间文本 / 记录结构
- 对大批量导出做分片让步,减少主线程长时间阻塞
安装方法
pnpm add @canvas-components/utils最低环境要求:
Node.js >= 18.12.0pnpm >= 9.0.0
使用方法
import { copyRows, exportTableToXlsx } from "@canvas-components/utils";
await copyRows([
["姓名", "年龄"],
["张三", 28],
["李四", 31],
]);
await exportTableToXlsx({
fileName: "users.xlsx",
rows: [
{ name: "张三", age: 28 },
{ name: "李四", age: 31 },
],
columns: [
{ key: "name", title: "姓名", value: (row) => row.name },
{ key: "age", title: "年龄", value: (row) => row.age },
],
});属性说明
XLSX 大数据导出
exportTableToXlsx 默认在数据达到 1 万行时尝试 Web Worker,工作表构建与 XLSX 编码在后台完成。业务 value 回调仍在主线程分批执行;每批确认后才发送下一批,避免一次性复制全部数据。SheetJS 随包内置,不依赖 CDN。
worker: "auto" | true | false:默认"auto";true始终尝试 Worker,false使用主线程。signal: AbortSignal:取消导出,Promise 以AbortError拒绝;Worker 编码期间也可取消。onProgress(progress):阶段为preparing、encoding、saving、done,包含全局completedRows、totalRows、实际是否使用worker,以及从 1 开始的fileIndex、fileCount。done表示全部文件已交给保存流程,不代表浏览器确认文件已落盘。footerRows: unknown[][]:追加汇总等尾行,无需改造原始行对象。maxRowsPerFile:每份文件的数据行上限,默认且最多 100,000 行(尾行计入,表头不计入)。maxCellsPerFile:每份文件的单元格预算,默认且最多 2,000,020 个(含表头),保证 20 列以内可以按十万行分文件;例如 40 列时每份最多 49,999 行。两个选项只能收紧安全上限。saveFile(blob, fileName, { fileIndex, fileCount }):可接管文件保存;等待回调完成后才开始下一份。不要在回调中累积保存所有 Blob。
Worker 不可用或启动被 CSP 阻止时回退到主线程分批构建;主线程最终编码仍为同步操作,不能在该阶段即时取消。Worker 运行中失败直接报错,不重复执行业务回调。
大数据自动拆成独立的 文件名_001.xlsx、文件名_002.xlsx 等文件;单文件保持原文件名。每份重复表头,汇总只在数据末尾追加,不重新按文件计算。只生成一份工作簿,结束后终止 Worker,默认下载撤销 Blob URL 后才开始下一份;不累积全部文件,也不合成大 ZIP。
浏览器可能要求允许“下载多个文件”,脚本不能确认是否被下载策略拦截;也可以通过 saveFile 接管保存。取消或失败会停止后续文件,已下载文件不会撤回。单元格文本超过 32,767 字符、单文件累计文本超过 16M UTF-16 码元时会报错,不静默截断;长文本数据可降低 maxRowsPerFile。内存安全取决于现有数据源及浏览器状态,千万行、多列数据仍建议服务端导出。
ExportTableColumn<Row>
| 属性 | 类型 | 说明 |
| ------- | -------------------------------------- | ------------------ |
| key | string | 列唯一标识 |
| title | string | 导出列标题 |
| value | (row: Row, index: number) => unknown | 从行数据中取导出值 |
ClipboardCellValue
支持的剪贴板单元格值类型:
type ClipboardCellValue = string | number | boolean | null | undefined;方法说明
剪贴板
| 方法 | 签名 | 说明 |
| ------------------------ | ------------------------------------------------- | ------------------------ |
| copyText | (text: string) => Promise<void> | 写入纯文本 |
| copyRows | (rows: ClipboardCellValue[][]) => Promise<void> | 把二维数据写入剪贴板 |
| copyJson | (value: unknown, space = 2) => Promise<void> | 写入 JSON 文本 |
| formatRowsForClipboard | (rows) => string | 把二维数据转成制表符文本 |
导出
| 方法 | 签名 | 说明 |
| ------------------------ | ------------------------------------------------------------ | --------------------------- |
| mapRowsToExportRecords | ({ rows, columns }) => Record<string, unknown>[] | 生成导出记录数组 |
| buildCsvContent | ({ rows, columns }) => string | 生成 CSV 文本 |
| serializeCsvRows | (rows, lineBreak?) => string | 将二维数据序列化为 CSV 文本 |
| buildTxtContent | ({ rows, columns }) => string | 生成 TXT 文本 |
| downloadJsonFile | ({ fileName, data, space? }) => Promise<void> | 下载 JSON |
| exportTableToCsv | ({ fileName, rows, columns }) => Promise<void> | 导出 CSV |
| exportTableToTxt | ({ fileName, rows, columns }) => Promise<void> | 导出 TXT |
| exportTableToXlsx | ({ fileName, rows, columns, sheetName? }) => Promise<void> | 导出 XLSX |
数据读取
| 方法 | 签名 | 说明 |
| --------------------- | --------------------------------- | -------------------------------------------- |
| getValueByDataIndex | (source, dataIndex?) => unknown | 通过字符串、数字或属性路径数组安全读取嵌套值 |
| stringifyDataIndex | (dataIndex) => string | 将属性路径转换为稳定字符串 |
| isSameDataIndex | (left, right) => boolean | 判断两个属性路径是否一致 |
日期时间
可从主入口或 @canvas-components/utils/date 子路径引入。
| 方法 | 签名 | 说明 |
| ------------------------- | --------------------------------------------- | ---------------------------------------------- |
| resolveDateValue | (value: unknown) => Date \| null | 将日期、时间戳或日期字符串解析为有效日期 |
| isDateTimeFormatPattern | (pattern: string) => boolean | 判断是否包含日期时间格式 token |
| formatDateTimeValue | (value, pattern, locale?) => string \| null | 按格式字符串输出日期时间,默认使用中文区域设置 |
常用 token 包括 YYYY、YY、M、MM、D、DD、ddd、dddd、H、HH、h、hh、m、mm、s、ss、SSS、A。方括号中的内容按普通文本输出,例如 YYYY年M月D日 [更新]。
数字格式
可从主入口或 @canvas-components/utils/number 子路径引入。
| 方法 | 签名 | 说明 |
| --------------------------- | ------------------------------------ | -------------------------------------------- |
| parseNumberValue | (value: unknown) => number \| null | 解析数字和带千分位的数字字符串 |
| formatNumberValue | (value, options?) => string | 格式化数字、金额和千分位数字 |
| formatPercentValue | (value, decimalPlaces?) => string | 将比例数值格式化为百分比 |
| formatScientificValue | (value, decimalPlaces?) => string | 格式化科学计数法 |
| formatCustomNumberPattern | (value, pattern) => string | 按常见表格数字 pattern 格式化 |
| formatChineseNumber | (value, style?) => string \| null | 将数字转换为普通或金融大写中文数字 |
| parseChineseNumber | (value) => number \| null | 将规范的普通或金融大写中文数字转为阿拉伯数字 |
金融大写使用规范数字字符,例如 918000 输出 玖拾壹万捌仟;不兼容形近字或错别字。
基础几何
| 方法 | 签名 | 说明 |
| --------------- | ------------------------------------- | ---------------------- |
| clamp | (value, minimum, maximum) => number | 将数值限制在闭区间内 |
| isPointInRect | (x, y, rect) => boolean | 判断坐标是否位于矩形内 |
适用场景
- 表格导出
- 系统复制功能
- 大批量数据下载
- 非 React 项目里的浏览器工具函数复用
