Core Docs
@skyroc/utils

Web

仅限浏览器环境的工具集,包含完整的文件下载策略、新窗口打开与 HTML class 切换

概述

Web 子模块通过独立的子路径 @skyroc/utils/web 导出,与主入口分离,避免在非浏览器环境(Node.js、SSR)引入 BOM API。

import { downloadFileFromUrl, openWindow, toggleHtmlClass } from '@skyroc/utils/web';

包含三个职责:

模块导出说明
downloaddownloadFileFromUrl 等 7 个函数多策略文件下载
windowopenWindow安全地在新窗口打开 URL
classtoggleHtmlClass切换 <html> 元素上的 class

文件下载

下载场景的难点在于:不同来源(URL / Base64 / Blob)、不同平台(iOS / 桌面 / CORS 限制)需要不同的处理策略。download 模块将这些复杂性封装在内部,对外提供清晰的函数边界。

选择哪个函数?

文件来源是什么?
  ├─ 普通 URL(http/https)    → downloadFileFromUrl
  ├─ 图片 URL(需转 base64)   → downloadFileFromImageUrl
  ├─ Base64 / DataURL          → downloadFileFromBase64
  ├─ Blob 对象                 → downloadFileFromBlob
  ├─ BlobPart(ArrayBuffer 等)→ downloadFileFromBlobPart
  └─ 自定义 href               → triggerDownload(底层)

downloadFileFromUrl(options) — 异步

通过 URL 下载文件,内置跨平台兼容逻辑:

  1. iOS / iPadOS → 直接 openWindowa[download] 在 iOS 上不可靠)
  2. 桌面端,CORS 允许fetch → blob → a[download](最稳定,可自定义文件名)
  3. 桌面端,CORS 不允许 → 回退 openWindow

文件名解析优先级:Content-Disposition 响应头 → 参数 fileName → URL 路径中的文件名。

import { downloadFileFromUrl } from '@skyroc/utils/web';

// 最简用法
await downloadFileFromUrl({ source: 'https://example.com/report.pdf' });

// 指定文件名
await downloadFileFromUrl({
  source: 'https://example.com/export?id=123',
  fileName: '月度报表.xlsx',
});

// 在当前 tab 打开(适合预览)
await downloadFileFromUrl({
  source: 'https://example.com/preview.pdf',
  target: '_self',
});
interface DownloadOptions {
  source: string;      // 文件 URL
  fileName?: string;   // 自定义文件名(可选)
  target?: string;     // 回退打开窗口的 target,默认 '_blank'
}

downloadFileFromBase64(options)

通过 Base64 / DataURL 下载文件,同步。

import { downloadFileFromBase64 } from '@skyroc/utils/web';

downloadFileFromBase64({
  source: 'data:application/pdf;base64,JVBERi0x...',
  fileName: 'document.pdf',
});

// 图片(省略 mimeType 前缀也可以,但推荐带完整 DataURL)
downloadFileFromBase64({
  source: 'data:image/png;base64,iVBORw0KGgo...',
  fileName: 'screenshot.png',
});

downloadFileFromImageUrl(options) — 异步

通过图片 URL 下载图片,内部用 Canvas 将图片转为 Base64 后下载。

跨域限制: 图片服务端必须返回 Access-Control-Allow-Origin 响应头,否则 Canvas 会被"污染"而抛错。

import { downloadFileFromImageUrl } from '@skyroc/utils/web';

await downloadFileFromImageUrl({
  source: 'https://cdn.example.com/avatar.png',
  fileName: 'my-avatar.png',
});

downloadFileFromBlob(options)

通过 Blob 对象下载,同步。适合服务端返回的二进制响应。

import { downloadFileFromBlob } from '@skyroc/utils/web';

// 配合 axios(responseType: 'blob')
const response = await axios.get('/api/export', { responseType: 'blob' });
downloadFileFromBlob({
  source: response.data,       // Blob
  fileName: '数据导出.xlsx',
});

downloadFileFromBlobPart(options)

通过 BlobPartstring | ArrayBuffer | Uint8Array 等)下载,同步。适合需要自行构造文件内容的场景。

import { downloadFileFromBlobPart } from '@skyroc/utils/web';

const csvContent = 'name,age\nAlice,30\nBob,25';
downloadFileFromBlobPart({
  source: csvContent,
  fileName: 'users.csv',
});

urlToBase64(url, mimeType?) — 异步

将图片 URL 转为 Base64 DataURL(底层实现)。跨域图片需要服务端允许 CORS。

import { urlToBase64 } from '@skyroc/utils/web';

const base64 = await urlToBase64('https://cdn.example.com/image.png');
// 'data:image/png;base64,...'

triggerDownload(href, fileName, revokeDelay?) — 底层

通用下载触发函数,通过动态创建 <a> 标签并模拟点击实现下载。是其他 download* 函数的内部实现。

一般不需要直接调用,除非需要传入已有的 blob URL 或 data URL:

import { triggerDownload } from '@skyroc/utils/web';

const blobUrl = URL.createObjectURL(myBlob);
triggerDownload(blobUrl, 'file.zip');
// blob URL 会在 150ms 后自动 revokeObjectURL

openWindow

import { openWindow } from '@skyroc/utils/web';

在新窗口(或指定 target)打开一个 URL,默认启用 noopener,noreferrer 安全策略防止 opener 劫持。

// 新 tab 打开(默认)
openWindow('https://docs.example.com');

// 当前 tab
openWindow('/settings', { target: '_self' });

// 关闭安全策略(需要 opener 引用时)
openWindow('https://external.com', { secure: false });
interface OpenWindowOptions {
  target?: '_blank' | '_parent' | '_self' | '_top' | string; // 默认 '_blank'
  secure?: boolean; // 默认 true,开启 noopener + noreferrer
}

toggleHtmlClass

import { toggleHtmlClass } from '@skyroc/utils/web';

切换 document.documentElement(即 <html> 标签)上的 class,常用于主题切换(暗色模式)。

const darkMode = toggleHtmlClass('dark');

darkMode.add();    // <html class="dark">
darkMode.remove(); // <html class="">

在 React 中配合主题状态使用:

import { useEffect } from 'react';
import { toggleHtmlClass } from '@skyroc/utils/web';

const dark = toggleHtmlClass('dark');

const ThemeWatcher = ({ isDark }: { isDark: boolean }) => {
  useEffect(() => {
    isDark ? dark.add() : dark.remove();
  }, [isDark]);

  return null;
};

On this page