/** * 文件下载 * *将实时创建标签并在下载完成后自动移除 * @param url 文件地址 * @param name 文件名 */ export function downloadFile(url: string, name?: string): void { if (!url) return; const element = document.createElement('a'); element.href = url; if (name) { element.download = name; } element.click(); element.remove(); } /** * 文件选择 * @param accept 支持的文件类型 * @param limit 文件大小限制(byte) * @returns 选中的文件域 */ export async function selectFile(accept?: string, limit?: number): Promise { const element = document.createElement('input'); element.type = 'file'; element.accept = accept ?? ''; try { return await new Promise((resolve, reject) => { element.onchange = () => { const file = element.files?.[0]; if (!file?.size) return resolve(); if (limit && limit < file.size) return reject(`文件大小不能超过${~~(limit / 1000)}KB`); const extension = file.name.split('.').pop()!.toLowerCase(); if (accept && !accept.toLowerCase().includes(extension)) return reject(`仅支持${accept}文件`); resolve(file); }; element.oncancel = () => resolve(); element.click(); }); } finally { element.onchange = null; element.oncancel = null; element.remove(); } } /** * Base64图片转二进制 * @param base64:Base64 图片数据 * @returns 二进制数据 */ export function base64ToBlob(base64: string): Blob | undefined { const [prefix, data] = base64?.split('base64,', 2) ?? []; const type = prefix?.match(/:(.*?);/)?.[1]; const str = atob(data ?? ''); if (!type || !str?.length) return; let n = str.length; const buffer = new Uint8Array(n); while (n--) { buffer[n] = str.charCodeAt(n); } return new Blob([buffer], { type }); } /** * 文本转二进制 * @param text 文本字符 * @returns 二进制数据 */ export function textToBlob(text: string): Blob | undefined { if (!text.length) return; return new Blob([text], { type: 'text/plain' }); } /** * 文本文件解码 * @param file 文件域 * @returns 文本字符串 */ export async function decodeTextFile(file: File): Promise { if (!file.size) return; const decoder = new TextDecoder(); const buffer = await file.arrayBuffer(); return decoder.decode(buffer); }